一般来说,是不安全的。
const [value, setValue] = useState("");
function test() {
console.log(value)
}
useEffect(() => {
test()
},[])
上述的代码,是有bug的。因为外部函数使用了state,而如果在useEffect中使用了省略函数,effect中很难知道外部函数使用了哪些state和porps。所以我们应该在effect内部去声明所需要的函数,这样就能更好看的看出effect依赖组件作用域的那些值。
const [value, setValue] = useState("");
useEffect(() => {
function test() {
console.log(value)
}
test()
},[value])
如果你指定了一个依赖列表作为useEffect、useLayoutEffect、useMemo、useCallBack、useImperativeHandle的最后一个参数,那么它必须包含回调中的所有值,并参与React数据流。这就包括props、state,以及任何由它衍生而来的东西。
只有当函数以及它所调用的函数不引用props、state以及由它们衍生而来的值时,才可以把它从依赖列表中省略。
常见数据请求问题:
function Demo ({ id }) {
const [value, setValue] = useState("");
asycn function test(){
const res = await fetch('http://XXX' + id);
const data = res.json();
setValue(data)
}
useEffect(() => {
test()
},[])
}
这里的外部函数使用了state,所以我们需要把外部函数拿到effect中,这样可以更好的看出使用了哪些state和props,并确保已经被声明了。
function Demo ({ id }) {
const [value, setValue] = useState("");
useEffect(() => {
asycn function test(){
const res = await fetch('http://XXX' + id);
const data = res.json();
setValue(data)
}
test()
},[value])
}
如果因为某些原因无法把一个函数引入到effect内部,其他解决方法:
- 可以尝试把函数移动到组件外,这样这个函数就不会依赖任何props和state,并且也不用出现在依赖列表中。
- 如果调用的方法是一个纯计算,并且可以在渲染时调用,你可以在effect之外调用它 , 并让 effect 依赖于它的返回值。
- 也可以把函数加入 effect 的依赖但把它的定义包裹进useCallback Hook。这就确保了它不随渲染而改变,除非它自身的依赖发生了改变:
function ProductPage({ productId }) {
// ✅ 用 useCallback 包裹以避免随渲染发生改变
const fetchProduct = useCallback(() => {
// ... Does something with productId ...
}, [productId]); // ✅ useCallback 的所有依赖都被指定了
return <ProductDetails fetchProduct={fetchProduct} />;
}
function ProductDetails({ fetchProduct }) {
useEffect(() => {
fetchProduct();
}, [fetchProduct]); // ✅ useEffect 的所有依赖都被指定了
// ...
}