onCallback React Hook - 最佳实践查询
onCallback React Hook - best practice query
这更像是一个最佳实践问题。但是我想知道 React 组件中的任何内联函数是否通常应该用 onCallback 包装以提高性能?在什么情况下我不会用 onCallback 包装这样的函数?
例如:
const ToolSearch = (props: ToolsSearchProps) => {
const handleOnClick = () => {
alert('do something');
}
return (
<NoCardOverflow>
<ToolSearchCollapse openState={filtersOpen} onClick={handleOnClick} />
</NoCardOverflow>
);
};
在这个例子中我应该这样做:
const ToolSearch = (props: ToolsSearchProps) => {
const handleOnClick = useCallback(() => {
alert('do something');
},[]);
return (
<NoCardOverflow>
<ToolSearchCollapse openState={filtersOpen} onClick={handleOnClick} />
</NoCardOverflow>
);
};
ToolSearchCollapse 是您的 child 组件,因此包装您的 handleClick 函数很有意义。因为每次 parent 组件 re-renders 都会将 handleclick 的新引用传递给 ToolSearchCollapse,并且您的 child 将 re-render时间 parent 状态发生变化(从未传递到 child 的状态)。使用 useCallback 将不允许创建新引用,因此您可以控制 child 应该呈现的时间。
如果您不将此 fn 传递给 child,我看不出有任何理由使用 useCallback。
我将尝试用一个例子来解释 useCallBack
。我们都知道 useCallBack
的定义,但是 何时使用 是这里的技巧部分。那么,让我举个例子。
const RenderText = React.memo(({ text }) => {
console.log(`Render ${text}`);
return (<div>{text}</div>);
});
const App = () => {
const [count, updateCount] = React.useState(0);
const [lists, updateLists] = React.useState(["list 1"]);
const addListItem = () => {
updateLists([...lists, "random"]);
};
return (
<div>
{`Current Count is ${count}`}
<button onClick={() => updateCount((prev) => prev + 1)}>Update Count</button>
{lists.map((item: string, index: number) => (
<RenderText key={index} text={item} />
))}
</div>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
jsFiddle: https://jsfiddle.net/enyctuLp/1/
上面有两种状态
- count - 数量
- 列表-数组
RenderText
只是呈现传递给它的文本。 (这是列表中的项目)。如果你点击Update Count
按钮,RenderText
不会re-render因为它独立于主要组件(App
)并且在updateCount
期间,只有App
组件将 re-render,因为它需要更新 count
值。
现在,将 addListItem
传递给 RenderText
组件并单击 Update Count
按钮,看看会发生什么。
jsFiddle: https://jsfiddle.net/enyctuLp/2/
你可以看到 RenderText
将 re-render 即使 list
数组没有变化,这是 BECAUSE :
- 更新计数后,
App
将 re-render
- 这将 re-render
addListItem
- 这导致
RenderText
到 re-render。
为了避免这种情况,我们应该使用 useCallBack
钩子。
jsFiddle: https://jsfiddle.net/enyctuLp/4/
现在,addListItem
函数已经被记忆化,它只会在依赖关系发生变化时发生变化。
这更像是一个最佳实践问题。但是我想知道 React 组件中的任何内联函数是否通常应该用 onCallback 包装以提高性能?在什么情况下我不会用 onCallback 包装这样的函数?
例如:
const ToolSearch = (props: ToolsSearchProps) => {
const handleOnClick = () => {
alert('do something');
}
return (
<NoCardOverflow>
<ToolSearchCollapse openState={filtersOpen} onClick={handleOnClick} />
</NoCardOverflow>
);
};
在这个例子中我应该这样做:
const ToolSearch = (props: ToolsSearchProps) => {
const handleOnClick = useCallback(() => {
alert('do something');
},[]);
return (
<NoCardOverflow>
<ToolSearchCollapse openState={filtersOpen} onClick={handleOnClick} />
</NoCardOverflow>
);
};
ToolSearchCollapse 是您的 child 组件,因此包装您的 handleClick 函数很有意义。因为每次 parent 组件 re-renders 都会将 handleclick 的新引用传递给 ToolSearchCollapse,并且您的 child 将 re-render时间 parent 状态发生变化(从未传递到 child 的状态)。使用 useCallback 将不允许创建新引用,因此您可以控制 child 应该呈现的时间。
如果您不将此 fn 传递给 child,我看不出有任何理由使用 useCallback。
我将尝试用一个例子来解释 useCallBack
。我们都知道 useCallBack
的定义,但是 何时使用 是这里的技巧部分。那么,让我举个例子。
const RenderText = React.memo(({ text }) => {
console.log(`Render ${text}`);
return (<div>{text}</div>);
});
const App = () => {
const [count, updateCount] = React.useState(0);
const [lists, updateLists] = React.useState(["list 1"]);
const addListItem = () => {
updateLists([...lists, "random"]);
};
return (
<div>
{`Current Count is ${count}`}
<button onClick={() => updateCount((prev) => prev + 1)}>Update Count</button>
{lists.map((item: string, index: number) => (
<RenderText key={index} text={item} />
))}
</div>
);
};
ReactDOM.render(<App />, document.querySelector("#app"));
jsFiddle: https://jsfiddle.net/enyctuLp/1/
上面有两种状态
- count - 数量
- 列表-数组
RenderText
只是呈现传递给它的文本。 (这是列表中的项目)。如果你点击Update Count
按钮,RenderText
不会re-render因为它独立于主要组件(App
)并且在updateCount
期间,只有App
组件将 re-render,因为它需要更新 count
值。
现在,将 addListItem
传递给 RenderText
组件并单击 Update Count
按钮,看看会发生什么。
jsFiddle: https://jsfiddle.net/enyctuLp/2/
你可以看到 RenderText
将 re-render 即使 list
数组没有变化,这是 BECAUSE :
- 更新计数后,
App
将 re-render - 这将 re-render
addListItem
- 这导致
RenderText
到 re-render。
为了避免这种情况,我们应该使用 useCallBack
钩子。
jsFiddle: https://jsfiddle.net/enyctuLp/4/
现在,addListItem
函数已经被记忆化,它只会在依赖关系发生变化时发生变化。