Javascript 如何只调用一次带有React useEffect的加载函数
React钩子将在每次更改时运行传入函数。可以对其进行优化,使其仅在所需属性更改时调用 如果我想从Javascript 如何只调用一次带有React useEffect的加载函数,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,React钩子将在每次更改时运行传入函数。可以对其进行优化,使其仅在所需属性更改时调用 如果我想从componentDidMount调用一个初始化函数,并且在发生更改时不再调用它,该怎么办?假设我想加载一个实体,但加载函数不需要来自组件的任何数据。我们如何使用useffecthook实现这一点 class MyComponent extends React.PureComponent { componentDidMount() { loadDataOnlyOnce();
componentDidMount
调用一个初始化函数,并且在发生更改时不再调用它,该怎么办?假设我想加载一个实体,但加载函数不需要来自组件的任何数据。我们如何使用useffect
hook实现这一点
class MyComponent extends React.PureComponent {
componentDidMount() {
loadDataOnlyOnce();
}
render() { ... }
}
使用钩子时,可以如下所示:
function MyComponent() {
useEffect(() => {
loadDataOnlyOnce(); // this will fire on every change :(
}, [...???]);
return (...);
}
如果只想在初始渲染后运行指定给
useffect
的函数,可以将空数组作为第二个参数
函数MyComponent(){
useffect(()=>{
loadDataOnlyOnce();
}, []);
返回{/*…*/};
}
将空数组作为第二个参数传递给useffect
。这有效地告诉React,引用以下内容:
这告诉React,您的效果不依赖于道具或状态的任何值,因此它永远不需要重新运行
下面是一个代码段,您可以运行它来显示它的工作原理:
函数应用程序(){
const[user,setUser]=React.useState(null);
React.useffect(()=>{
取('https://randomuser.me/api/')
.then(results=>results.json())
。然后(数据=>{
setUser(data.results[0]);
});
},[]);//将空数组传递到装载时仅运行一次。
返回
{user?user.name.first:'正在加载…'}
;
}
ReactDOM.render(,document.getElementById('app'))代码>
TL;DR
useffect(yourCallback,[])
-将仅在第一次渲染后触发回调
详细说明
默认情况下,useffect
在每次渲染组件后运行(从而产生效果)
在组件中放置useffect
时,您会告诉React您希望作为效果运行回调。React将在渲染和执行DOM更新后运行效果
如果只传递回调-回调将在每次渲染后运行
如果传递第二个参数(数组),React将在第一次渲染后以及每次更改数组中的一个元素时运行回调。例如,当放置useffect(()=>console.log('hello'),[someVar,someOtherVar])
时,回调将在第一次渲染后运行,并且在任何一次渲染后,someVar
或someOtherVar
中的一次被更改后运行
通过向第二个参数传递一个空数组,React将在每次渲染数组后进行比较,并将看到没有任何更改,因此仅在第一次渲染后调用回调。useMountEffect hook
组件挂载后只运行一次函数是一种常见的模式,它证明了它自己的钩子隐藏了实现细节
constusemounteffect=(乐趣)=>useffect(乐趣,[]
在任何功能组件中使用它
function MyComponent() {
useMountEffect(function) // function will run only once after it has mounted.
return <div>...</div>;
}
函数MyComponent(){
useMountEffect(函数)//函数在装入后只运行一次。
返回。。。;
}
关于useMountEffect挂钩
当将useffect
与第二个数组参数一起使用时,React将在装载(初始渲染)后以及数组中的值更改后运行回调。因为我们传递了一个空数组,所以它只能在装载后运行 我喜欢定义一个mount
函数,它会像useMount
一样欺骗EsLint,我发现它更容易解释
const mount = () => {
console.log('mounted')
// ...
const unmount = () => {
console.log('unmounted')
// ...
}
return unmount
}
useEffect(mount, [])
将依赖项数组留空。希望这能帮助你更好地理解
useEffect(() => {
doSomething()
}, [])
空依赖项数组在装载时仅运行一次
useEffect(() => {
doSomething(value)
}, [value])
将值作为依赖项传递。如果自上次以来依赖项已更改,则该效果将再次运行
useEffect(() => {
doSomething(value)
})
没有依赖关系。每次渲染后都会调用该函数
function useOnceCall(cb, condition = true) {
const isCalledRef = React.useRef(false);
React.useEffect(() => {
if (condition && !isCalledRef.current) {
isCalledRef.current = true;
cb();
}
}, [cb, condition]);
}
并使用它
useOnceCall(() => {
console.log('called');
})
或
或者,如果存在用于获取数据的参数(例如用户id),则可以在该数组中传递用户id,如果该用户id发生更改,则组件将重新提取数据。很多用例都是这样工作的。是的。。。关于跳绳的更多信息记录在这里:这似乎是最简单的答案,但ESLint抱怨。。。请参阅此线程的其他答案,将loadDataOnlyOnce传递到dependencies数组中即可。这行得通吗?不行,因为当loadDataOnlyOnce更改时(本例中没有,但lint不会抱怨非局部变量),它会重新运行效果。解决方案可能是为钩子创建一个单独的函数,就像这里的另一个答案一样(有效地愚弄了ESLint),或者在第一次运行后设置一个带有布尔值的useRef
,如果设置了,就不再运行。我非常喜欢您的答案,因为ESLint规则“react hooks/deps”对于空的依赖项列表,将始终失败。例如,著名的CreateReact应用程序模板将强制执行该规则。完全同意@Dynalon。这应该是可接受的解决方案,因为它不干扰ESLint规则。现在,当效果函数需要道具提供的内容时,您可以使用useMount
,但即使该值在没有linter warnig的情况下更改,也不需要再次运行:useffect(()=>console.log(props.val),[])
将有缺少依赖项警告,但使用装载(()=>console.log(props.val))
不会引起警告,但“确实有效”。我不确定并发模式是否会有问题。我不太明白“react hooks/deps”
仍然抱怨const useMountEffect=(fun)=>useffect(fun,[])中的空数组。
谢谢!尽管我认为这指向了“react hooks/deps”
中的一个缺陷,特别是因为这是在挂载上运行东西的标准方式。这个“解决方案”在功能上把问题从组件转移到其他地方,而不是用空的dep从根本上解决问题。谢谢!救了我一天。
useOnceCall(()=>{
console.log('Fetched Data');
}, isFetched);