[英]Custom React hook, infinite loop only if I add the second dependency. Bug or something I can't understand?
I've made a really simple React hook.我做了一个非常简单的 React 钩子。 That's something seen on many guides and websites:
这是在许多指南和网站上看到的:
import { useEffect, useState } from 'react';
import axios from 'axios';
export const useFetchRemote = (remote, options, initialDataState) => {
const [data, setData] = useState(initialDataState);
useEffect(() => {
const fetchData = async () => {
const result = await axios.get(remote, options);
setData(result.data);
};
fetchData();
}, [remote]);
return data;
};
Example usage:示例用法:
import { useFetchRemote } from '../utils';
export const UserList = () => {
const users = useFetchRemote('/api/users', {}, []);
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>}
</ul>
);
}
This is working .这是有效的。 If I understand correctly:
如果我理解正确:
useEffect(() => { /*...*/ })
, setting the state into the function would trigger a re-render, calling useEffect
again, in an infinite loop.useEffect(() => { /*...*/ })
这样的依赖项,将 state 设置为 function 将触发重新渲染,在无限循环中再次调用useEffect
。useEffect(() => { /*...*/ }, [])
, my function will be called only the "very first time" component is mounted.useEffect(() => { /*...*/ }, [])
类的空依赖项,我的 function 将仅在安装“非常第一次”组件时被调用。 So, in my case, remote
is a dependency.所以,就我而言,
remote
是一个依赖项。 My function should be called again if remote changes.如果远程更改,应该再次调用我的 function。 This is true also for
options
.对于
options
也是如此。 If I add also options
, the infinite loop starts.如果我还添加
options
,则无限循环开始。 I can't understand... why this is happening?我不明白……为什么会这样?
export const useFetchRemote = (remote, options, initialDataState) => {
// ...
useEffect(() => {
// ...
}, [remote, options]);
// ...
};
The infinite loop is caused by the fact that your options
parameter is an object literal, which creates a new reference on every render of UserList
.无限循环是由于您的
options
参数是 object 文字这一事实引起的,它会在UserList
的每个渲染上创建一个新引用。 Either create a constant reference by defining a constant outside the scope of UserList
like this:通过在
UserList
的 scope 之外定义一个常量来创建常量引用,如下所示:
const options = {};
const initialDataState = [];
export const UserList = () => {
// or for variable options instead...
// const [options, setOptions] = useState({});
const users = useFetchRemote('/api/users', options, initialDataState);
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>}
</ul>
);
}
or if you intend the options
parameter to be effectively constant for each usage of the userFetchRemote()
hook, you can do the equivalent of initializing props into state and prevent the reference from updating on every render:或者,如果您希望
options
参数对于userFetchRemote()
钩子的每次使用都有效地保持不变,您可以执行将道具初始化为 state 的等效操作,并防止在每次渲染时更新引用:
export const useFetchRemote = (remote, options, initialDataState) => {
const [optionsState] = useState(options);
const [data, setData] = useState(initialDataState);
useEffect(() => {
const fetchData = async () => {
const result = await axios.get(remote, optionsState);
setData(result.data);
};
fetchData();
}, [remote, optionsState]);
// ---------^
return data;
};
This second approach will prevent a new fetch from occuring though, if the options are dynamically changed on a particular call site of useFetchRemote()
.但是,如果选项在
useFetchRemote()
的特定调用站点上动态更改,则第二种方法将防止发生新的提取。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.