Dáv*_*nár 133 javascript reactjs react-hooks
该useEffect阵营钩将运行在功能上传递的每一个变化.这可以进行优化,只有在所需的属性发生变化时才能调用它.
如果我想调用初始化函数componentDidMount而不是在更改时再调用它会怎么样?假设我想加载一个实体,但加载函数不需要组件中的任何数据.我们怎么能用useEffect钩子做这个?
class MyComponent extends React.PureComponent {
componentDidMount() {
loadDataOnlyOnce();
}
render() { ... }
}
Run Code Online (Sandbox Code Playgroud)
使用钩子,这可能是这样的:
function MyComponent() {
useEffect(() => {
loadDataOnlyOnce(); // this will fire on every change :(
}, [...???]);
return (...);
}
Run Code Online (Sandbox Code Playgroud)
Tho*_*lle 255
如果你只想useEffect在初始渲染之后运行给定的函数,你可以给它一个空数组作为第二个参数.
function MyComponent() {
useEffect(() => {
loadDataOnlyOnce();
}, []);
return <div> {/* ... */} </div>;
}
Run Code Online (Sandbox Code Playgroud)
wua*_*min 92
我们必须停止思考组件生命周期方法(即componentDidMount)。我们必须开始考虑效果。React 效果与旧式的类生命周期方法不同。
默认情况下,效果在每个渲染周期后运行,但可以选择退出此行为。要选择退出,您可以定义依赖关系,这意味着仅当对依赖关系之一进行更改时才会产生效果。
如果您明确定义某个效果没有依赖性,则该效果仅在第一个渲染周期之后运行一次。
第一个解决方案(符合 ESLint)
因此,您的示例的第一个解决方案如下:
function MyComponent() {
const loadDataOnlyOnce = () => {
console.log("loadDataOnlyOnce");
};
useEffect(() => {
loadDataOnlyOnce(); // this will fire only on first render
}, []);
return (...);
}
Run Code Online (Sandbox Code Playgroud)
But then the React Hooks ESLint plugin will complain with something like that:
React Hook useEffect has missing dependency: loadDataOnlyOnce. Either include it or remove the dependency array.
At first this warning seems annoying, but please don't ignore it. It helps you code better and saves you from "stale closures". If you don't know what "stale closures" are, please read this great post.
2nd solution (the right way, if dependency is not dependent on component)
If we add loadDataOnlyOnce to the dependency array, our effect will run after every render-cycle, because the reference of loadDataOnlyOnce changes on every render, because the function is destroyed(garbarge-collected) and a new function is created, but that's exactly what we don't want.
我们必须loadDataOnlyOnce在渲染周期中保持相同的引用。
所以只需移动上面的函数定义即可:
const loadDataOnlyOnce = () => {
console.log("loadDataOnlyOnce");
};
function MyComponent() {
useEffect(() => {
loadDataOnlyOnce(); // this will fire only on first render
}, [loadDataOnlyOnce]);
return (...);
}
Run Code Online (Sandbox Code Playgroud)
通过此更改,您可以确保引用loadDataOnlyOnce will never change. Therefore you can also safely add the reference to the dependency array.
第三种解决方案(正确的方法,如果依赖项依赖于组件)
如果效果(loadDataOnlyOnce)的依赖依赖于组件(需要 props 或 state),则有 React 的内置useCallback-Hook。
-Hook 的基本意义useCallback是在渲染周期期间保持函数的引用相同。
function MyComponent() {
const [state, setState] = useState("state");
const loadDataOnlyOnce = useCallback(() => {
console.log(`I need ${state}!!`);
}, [state]);
useEffect(() => {
loadDataOnlyOnce(); // this will fire only when loadDataOnlyOnce-reference changes
}, [loadDataOnlyOnce]);
return (...);
}
Run Code Online (Sandbox Code Playgroud)
Eda*_*rit 52
TL; DR
useEffect(yourCallback, []) -仅在第一次渲染后才触发回调。
详细说明
useEffect默认情况下,在每次渲染组件后运行(因此会产生效果)。
当放置useEffect到组件中时,您告诉React您想运行回调作为效果。React将在渲染后和执行DOM更新后运行效果。
如果仅传递回调,则该回调将在每次渲染后运行。
如果传递第二个参数(数组),React将在第一个渲染之后以及每次更改数组中的一个元素时运行回调。例如,在放置时useEffect(() => console.log('hello'), [someVar, someOtherVar])-回调将在第一个渲染之后someVar以及someOtherVar更改或的任何渲染之后运行。
通过向第二个参数传递一个空数组,React将在每次渲染该数组之后进行比较,并且不会看到任何更改,因此仅在第一个渲染之后才调用回调。
Ben*_*arp 26
在组件挂载后仅运行一次功能是一种常见的模式,它证明了自己的钩子隐藏了实现细节。
const useMountEffect = (fun) => useEffect(fun, [])
Run Code Online (Sandbox Code Playgroud)
在任何功能组件中使用它。
function MyComponent() {
useMountEffect(function) // function will run only once after it has mounted.
return <div>...</div>;
}
Run Code Online (Sandbox Code Playgroud)
关于useMountEffect挂钩
当useEffect与第二个数组参数一起使用时,React将在挂载(初始渲染)后和数组中的值更改后运行回调。由于我们传递了一个空数组,因此它将仅在安装后运行。
Yan*_*Tay 15
传递一个空数组作为第二个参数useEffect.这有效地告诉React,引用文档:
这告诉React你的效果不依赖于来自props或state的任何值,所以它永远不需要重新运行.
这是一个代码片段,您可以运行它以显示它的工作原理:
function App() {
const [user, setUser] = React.useState(null);
React.useEffect(() => {
fetch('https://randomuser.me/api/')
.then(results => results.json())
.then(data => {
setUser(data.results[0]);
});
}, []); // Pass empty array to only run once on mount.
return <div>
{user ? user.name.first : 'Loading...'}
</div>;
}
ReactDOM.render(<App/>, document.getElementById('app'));Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/react@16.7.0-alpha.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.7.0-alpha.0/umd/react-dom.development.js"></script>
<div id="app"></div>Run Code Online (Sandbox Code Playgroud)
Gno*_*por 15
我在使用 React 18 时遇到了这个问题。我是这样处理的:
import { useEffect, useRef } from "react";
export default function Component() {
const wasCalled = useRef(false);
useEffect(() => {
if(wasCalled.current) return;
wasCalled.current = true;
/* CODE THAT SHOULD RUN ONCE */
}, []);
return <div> content </div>;
}
Run Code Online (Sandbox Code Playgroud)
在这里查看他们如何解释为什么 useEffect 被多次调用。
eco*_*gic 10
我喜欢定义一个mount函数,它以同样的方式欺骗 EsLint useMount,我发现它更不言自明。
const mount = () => {
console.log('mounted')
// ...
const unmount = () => {
console.log('unmounted')
// ...
}
return unmount
}
useEffect(mount, [])
Run Code Online (Sandbox Code Playgroud)
Yas*_*glu 10
function useOnceCall(cb, condition = true) {
const isCalledRef = React.useRef(false);
React.useEffect(() => {
if (condition && !isCalledRef.current) {
isCalledRef.current = true;
cb();
}
}, [cb, condition]);
}
Run Code Online (Sandbox Code Playgroud)
并使用它。
useOnceCall(() => {
console.log('called');
})
Run Code Online (Sandbox Code Playgroud)
或者
useOnceCall(()=>{
console.log('Fetched Data');
}, isFetched);
Run Code Online (Sandbox Code Playgroud)
将依赖项数组留空。希望这能帮助您更好地理解。
useEffect(() => {
doSomething()
}, [])
Run Code Online (Sandbox Code Playgroud)
空依赖项数组仅在 Mount 上运行一次
useEffect(() => {
doSomething(value)
}, [value])
Run Code Online (Sandbox Code Playgroud)
value作为依赖传递。如果自上次以来依赖项已更改,则效果将再次运行。
useEffect(() => {
doSomething(value)
})
Run Code Online (Sandbox Code Playgroud)
没有依赖性。每次渲染后都会调用此函数。
| 归档时间: |
|
| 查看次数: |
63144 次 |
| 最近记录: |