考虑这个例子:
let memoizedCb = React.useCallback(
memoize((param) => () => someFunction(param)),
[]
);
Run Code Online (Sandbox Code Playgroud)
哪里memoize来自外部库,例如“fast-memoize”。上面的代码给出了警告:
React Hook useCallback 收到一个依赖项未知的函数。改为传递内联函数
我发现这个线程,如果我们适应我的用例,会建议将此作为解决方案(如果我没有错的话):
const memoizedCb = React.useMemo(
() => memoize((param) => () => someFunction(param)),
[]
);
Run Code Online (Sandbox Code Playgroud)
警告是关于什么的?为什么要useMemo解决这个问题?
注意:someFunction在函数组件之外定义,因此不需要将其作为依赖项。
为什么在将函数表达式传递到 useEffect 依赖项数组时会创建无限循环?函数表达式不会改变组件状态,它只是引用它。
// component has one prop called => sections
const markup = (count) => {
const stringCountCorrection = count + 1;
return (
// Some markup that references the sections prop
);
};
// Creates infinite loop
useEffect(() => {
if (sections.length) {
const sectionsWithMarkup = sections.map((section, index)=> markup(index));
setSectionBlocks(blocks => [...blocks, ...sectionsWithMarkup]);
} else {
setSectionBlocks(blocks => []);
}
}, [sections, markup]);
Run Code Online (Sandbox Code Playgroud)
如果标记改变了状态,我可以理解为什么它会创建一个无限循环,但它不是简单地引用部分属性。
对于那些正在寻找解决此问题的方法的人
const markup = useCallback((count) => {
const stringCountCorrection = count + 1;
return …Run Code Online (Sandbox Code Playgroud) 假设我们有这样的组件
const Example = () => {
const [counter, setCounter] = useState(0);
const increment = () => setCounter(counter => counter + 1);
return (
<div>
<Button onClick={increment} />
<div>{counter}</div>
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
当我将onClick处理程序作为箭头函数传递时,我eslint抛出一个警告:
error JSX props should not use arrow functions react/jsx-no-bind
Run Code Online (Sandbox Code Playgroud)
正如我从这篇文章的答案中读到的:https : //stackoverflow.com/questions/36677733/why-shouldnt-jsx-props-use-arrow-functions-or-bind# :~: text=Why%20you%20shouldn 't%20use,previous%20function%20is%20garbage%20collected。
简短的回答是因为每次都会重新创建箭头函数,这会损害性能。这篇文章提出的一个解决方案是用空数组包装在useCallback钩子中。当我改成这个时,eslint 警告就真的消失了。
const Example = () => {
const [counter, setCounter] = useState(0);
const increment = useCallback(() => setCounter(counter => counter + …Run Code Online (Sandbox Code Playgroud) 将回调传递给组件时,我应该使用useCallback钩子返回一个记忆化的回调(以防止不必要的渲染):
import doSomething from "./doSomething";
const FrequentlyRerenders = ({ id }) => {
const onEvent = useCallback(() => doSomething(id), [id]);
return (
<ExpensiveComponent onEvent={ onEvent } />
);
};
Run Code Online (Sandbox Code Playgroud)
但是如果我使用地图呢?例如:
import doSomething from "./doSomething";
const FrequentlyRerendersMap = ({ ids }) => {
return ids.map(id => {
const onEvent = useCallback(() => doSomething(id), [id]);
return (
<ExpensiveComponent key={id} onEvent={ onEvent } />
);
});
};
Run Code Online (Sandbox Code Playgroud)
我应该如何正确使用useCallback?以上是传递多个回调的正确方法吗?它真的有效并且知道根据数组的一个项目来记忆每个回调吗?
据我所知,每当组件重新渲染时,都会重新生成在 React 的功能组件中定义的函数。由于 useCallback 可以由特定依赖项触发,因此可以防止这些函数不必要的重新生成。我应该将它们中的每一个都包装在 useCallback 中,并传递相关的依赖项吗?
import React from 'react'
const Comp = () => {
const fn1 = useCallback(
()=>{
// do something
???}, [dependency1])
const fn2 = useCallback(
()=>{
// do something
???}, [dependency2])
return (
//something
)
}
Run Code Online (Sandbox Code Playgroud) 我最近正在使用 React Hooks 重构一个 Web 应用程序。我遇到了一个问题useCallback. 基于Kent的描述:https : //kentcddodds.com/blog/usememo-and-usecallback,useCallback就是将相同的函数引用传递给子组件,避免子组件的重新渲染,使性能更好. 但是,它与React.memo. 正如肯特所说:
大多数时候你不应该去优化不必要的渲染。React 非常快,我能想到很多比优化这样的事情更好的事情。事实上,用我将要展示的东西来优化东西的需要是如此罕见,以至于我真的从来不需要这样做......
所以,我的问题是:我声称我们useCallback通常不需要使用是否正确?除非回调创建起来很昂贵,使用useCallback避免为每个渲染重新创建回调。
比如说,对于2 行或更少行的onClickoronChange事件处理程序,我们不useCallback应该用它来包装它吗?
这很可能是一个愚蠢的问题——我的理解是,任何引发副作用的事情都应该用 来处理useEffect。我想知道这种理解是否正确。特别是在进行 API 调用的情况下——在钩子中进行 API 调用好吗useCallback?
I don't understand why useCallback always returns a new ref each time one of the deps is updated. It results in many re-render that React.memo() could have avoided.
What is, if any, the problem with this implementation of useCallback?
export function useCallback(callback) {
const callbackRef = useRef();
callbackRef.current = callback;
return useState(() =>
(...args) => callbackRef.current(...args)
)[0];
}
Run Code Online (Sandbox Code Playgroud)
Using this instead of the built-in implementation sure has a significant positive impact on performance.
There is no reason …
我正在尝试使用 React hooks 来记忆回调。此回调专门使用在对象上定义的函数。
const setValue = useCallback((value) => {
field.setValue(key, value);
}, [field.setValue, key]);
Run Code Online (Sandbox Code Playgroud)
这会触发 Eslint 规则react-hooks/exhaustive-deps。
它想让我进去[field, key]。
如果我将代码更改为以下内容,即使看起来等效,我也不会收到警告:
const { setValue: setFieldValue } = field;
const setValue = useCallback((value) => {
setFieldValue(key, value);
}, [setFieldValue, key]);
Run Code Online (Sandbox Code Playgroud)
为什么 Eslint 在第一个示例中警告我?
在这种情况下我可以安全地忽略它吗?
我的场景很少,我想了解渲染和性能方面的差异。
下面显示的示例是一个简单的函数,但也请考虑一个更复杂的函数以及异步函数。
场景 1:定义函数并在 useEffect 中调用它。
useEffect(() => {
function getBooks() {
console.log('I get books!');
}
getBooks();
}, []);
Run Code Online (Sandbox Code Playgroud)
场景 2:在 UseEffect 外部定义函数并在其内部调用它。
function getBooks() {
console.log('I get books!');
}
useEffect(() => {
getBooks();
}, []);
Run Code Online (Sandbox Code Playgroud)
场景 3:使用 useCallback 在 UseEffect 外部定义函数并在其内部调用它。
const getBooks = useCallback(() => {
console.log('I get books!');
}, []);
useEffect(() => {
getBooks();
}, []);
Run Code Online (Sandbox Code Playgroud)
场景 4:使用 useCallback 在 UseEffect 中定义一个函数,并在 UseEffect 中调用它。
useEffect(() => {
const getBooks = useCallback(() => { …Run Code Online (Sandbox Code Playgroud) usecallback ×10
react-hooks ×9
reactjs ×9
javascript ×3
use-effect ×3
eslint ×1
side-effects ×1
typescript ×1