闽公网安备 35020302035485号
我们大多数人都知道虚拟 DOM 是如何工作的,但最重要的是检测何时触发树比较。当我们可以跟踪它时,我们可以控制组件的重新渲染,并最终防止意外的性能流。令人惊讶的是,它并不难捕捉。
.首先,将 React Devtool 扩展添加到浏览器。
.然后打开浏览器开发者工具(在 Chrome 中是 Option + ⌘ + J(在 macOS 上),或 Shift + CTRL + J(在 Windows/Linux 上)。那么,解决方案是什么?解决方法是通过将组件的一部分和它的一些状态移动到它自己的子组件中来分离状态上下文,现在,让我们看一下这个例子:假设我们有一个带有搜索过滤器的表格组件。搜索过滤器是一个受控输入,其状态在输入文本更改后更新。
这是它的样子:



const {someState, setSomeState} = useState('')
const {otherState, setOtherState} = useState('')
const foo = () => {console.log(someState)}
这是最常见的例子。我们有依赖于状态 someState 的 foo。当 someState 改变时,它将重新创建 foo 的新实例。const {someState, setSomeState} = useState('')
const {otherState, setOtherState} = useState('')
const foo = useCallback(() => {console.log(someState)}, [someState])
在此示例中,我们将依赖项数组传递给 useCallback 挂钩。更好的是,foo 将避免其他状态更改。另一种选择是使用 useRef。useRef——你可以把它想象成和 useState 一样,但不会触发组件重新渲染(UI 不会更新)。useRef 没有依赖列表,所以我们需要传递 someState as foo 属性:/* 堆代码 duidaima.com */
const {someState, setSomeState} = useState('')
const {otherState, setOtherState} = useState('')
const foo = useRef((currentSomeState) => {console.log(currentSomeState)}).current;
在这种情况下,我们根本不会重新创建 foo 实例。const PageComponent = React.lazy(() => import('./PageComponent'));
稍后我们可以使用 <Suspense/> 在页面组件尚未准备好时,显示一些加载动画。<Suspense fallback={<div>Loading...</div>}>
<PageComponent />
</Suspense>
这并不意味着我们必须在任何地方都使用 Lazy load 组件,当我们在不会对性能造成太大损害的地方使用它时,它可能会导致过度工程。另一种场景是一些组件可能默认隐藏在 UI 中,所以我们不必等待它们。例如模态窗口、对话框、抽屉和可折叠的侧面板。延迟加载页面组件和隐藏的 UI 组件。<ul>
<li>Item 1</li> <--- | Want to move it to child <Li> |
<li>Item 2</li> <--- | |
</ul>
因此,当我们将 <li> 移动到单独的组件中时,例如:const Li = () => {
return (
<div>
<li>Item 1</li>
<li>Item 2</li>
</div>
)
}
.
并改变它:<ul>
<Li/>
</ul>
渲染后,它看起来像这样:<ul>
<div>
<li>Item 1</li>
<li>Item 2</li>
</div>
</ul>
这将创建一个我们不需要的额外 <div> 节点。这将使我们的 DOM 树更加嵌套,从而减慢协调过程。相反, 我们可以将我们的<div> 子元素包装到 Fragment 中。最初,Fragment 允许您对 DOM 元素进行分组,插入后只会导致一次重排。在 React 中,Fragment 也会让你减少不必要的节点。当你想对元素进行分组时,你唯一需要做的就是使用 Fragment 而不是 <div> :const Li = () => {
return (
<> /* or <React.Fragment>, or <Fragment>*/
<li>堆代码</li>
<li>duidaima.com</li>
</>
)
}
就是这样,就这么简单。如果要对元素进行分组以减少节点数,请使用 Fragment。<ul>
<li key="1">Item 1</li>
<li key="2">Item 2</li>
</ul>
React 中的关键是唯一标识符,它帮助 React 指向列表中的正确元素并更新正确的元素。如果我们使用索引作为列表中的键,比如:<ul>
{[1, 2].map((val, index) => <li key={index}>Item {val}</li>)}
</ul>
我们将元素映射到它的索引。但是如果我们有排序,列表中元素的顺序可能会改变,初始键将不再指向正确的元素。始终使用唯一 id 作为列出元素的键,如果对象没有它,您可以使用外部库显式分配,如 uid。const Input = ({ onChange, ...props }) => (
<input {...props} onChange={e => onChange(e.target.value)}/>
);
它不仅迫使您猜测实际输入接收到的属性是什么,而且还会在输入元素中创建一堆您不一定需要的属性。让它明确,并且不要害怕根据需要传递尽可能多的属性,您总是可以将它们分组到某个对象中:const Input = ({ onChange, inputProps: {value, type, className} }) => (
<input className={className} type={type} value={value} onChange={e => onChange(e.target.value)}/>
);
很好,现在更具可读性。永远不要spread props,分别传递每个属性。