让我说一下
// Get a hook function
const {
useState,
useEffect
} = React;
const Example = ({
title
}) => {
const [formVal, setFormVal] = useState("")
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1)
// now use increment as just the cb for useeffect
useEffect(increment, [formVal])
return ( <
div >
<input onChange={(e) => setFormVal(e)} placeholder="test"/>
<
p > {
title
} < /p> <
p > You interacted {
count
}
times < /p> <
button onClick = {
increment
} >
Click me <
/button> < /
div >
);
};
// Render it
ReactDOM.render( <
Example title = "Example using Hooks:" / > ,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
我没有在increment
匿名回调中调用useEffect
,而是将整个内容作为第一个参数。我的问题是,这是否消除了将increment
包装到useCallback中的需要?
请注意,这是一个超级设计的示例,在此假设同时发生了其他重新渲染,并且目标是不要有无用的提交或重新渲染。
答案 0 :(得分:1)
useEffect和useCallback之间有区别。
当依赖项数组更改时,useEffect调用函数回调。当依赖项数组更改时,useCallback会使用newclosure重新创建该函数。同样useCallback返回一个函数useEffect没有
因此,即使您可以将增量传递给useEffect来实际执行该函数,它也不等同于useCallback,其中在依赖项数组发生更改时才重新创建该函数。在您的情况下,每个渲染上按钮元素的增量功能引用将有所不同
实现上述代码的最佳方法是
// Get a hook function
const {
useState,
useEffect,
useCallback
} = React;
const Example = ({
title
}) => {
const [formVal, setFormVal] = useState("")
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount(prevCount => prevCount + 1), [])
useEffect(increment, [formVal])
return ( <
div >
<input onChange={(e) => setFormVal(e)} placeholder="test"/>
<
p > {
title
} < /p> <
p > You interacted {
count
}
times < /p> <
button onClick = {
increment
} >
Click me <
/button> < /
div >
);
};
// Render it
ReactDOM.render( <
Example title = "Example using Hooks:" / > ,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>
即使您以增量或正常回调传递给useEffect,也仅在依赖项数组更改时更改useEffect用法的函数引用
答案 1 :(得分:1)
将函数传递给UseEffect是否有效?
是的。主要目的是保持功能的可重用性。确保它不返回任何内容/ / void
或无参数函数() => {...}
作为清除。否则,React会发出控制台错误。
这可以代替useCallback吗?
不。在useEffect
之后,挂钩的行为完全相同:
const increment = () => setCount(count + 1) // declared somewhere inside component
useEffect(increment, [formVal])
useEffect(() => setCount(count + 1), [formVal]) // inline variant of increment
在两个版本的每个渲染周期中都会创建一个新函数。 useEffect
在渲染后立即调用此传入的函数,只要依赖项数组的一项(formVal
)发生变化-不 {{1 }}。
increment
中缺少依赖项有一个细微的错误:目前,useEffect
引用了效果中的陈旧值。 count
也需要useEffect
作为依赖项,因为count
使用了它。您可以内联increment
效果回调,ESLint会警告您:increment
。插图:
React Hook useEffect has a missing dependency: 'count'
const Example = () => {
const [count, setCount] = React.useState(0);
const increment = () => {
// count dependency is missing / state closure scope
// => state will always be reset to initial count value
// we could use funtional updater, but this is just for demonstration
const handle = setInterval(() => setCount(count + 1), 2000);
return () => clearInterval(handle);
};
React.useEffect(increment, []);
// this triggers ESLint react hooks warning (ESLint not supported on SO)
// useEffect(() => { count; }, []);
return (
<div>
<p>You interacted {count} times</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<p>Click the button. The interval resets counter every 2 sec. because of a stale count value</p>
</div>
);
};
ReactDOM.render(<Example />, document.getElementById("root"));
在您的情况下,无需将<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script>
<div id="root"></div>
与useCallback
一起使用。请执行以下任一操作:
increment
为完善起见,// Add count effect dependency
const increment = () => setCount(count + 1)
useEffect(increment, [count, formVal])
// or use functional updater of `useState`
const increment = () => setCount(prev => prev + 1)
useEffect(increment, [formVal])
解决方案:
useCallback
const increment = useCallback(() => setCount(count + 1), [count])
useEffect(increment, [increment, formVal])
调用由其依赖项数组确定。以及useEffect
和原始DOM节点are cheap in terms of performance的内联点击回调。因此,您不需要button
。
如果useCallback
实现非常简单,您甚至可以在所有情况下内联它。