在React的官方文档中提到了-
如果你熟悉React类的生命周期方法,你可以思考 将useEffect钩子作为componentDidMount, componentDidUpdate和 componentWillUnmount总和。
我的问题是-我们如何在钩子中使用componentWillMount()生命周期方法?
在React的官方文档中提到了-
如果你熟悉React类的生命周期方法,你可以思考 将useEffect钩子作为componentDidMount, componentDidUpdate和 componentWillUnmount总和。
我的问题是-我们如何在钩子中使用componentWillMount()生命周期方法?
当前回答
考虑到
componentWillMount已弃用(1,2,3),建议的替换是在构造函数中执行代码 在函数组件的return语句之前执行的代码在呈现之前隐式运行 与挂载类组件大致相当的是函数组件的初始调用 目标是在UI更新之前执行一些代码一次
解决办法是
在函数组件的主体中只运行一次函数。这可以通过useState、useMemo或useEffect来实现,具体取决于用例所需的时间。
由于代码需要在将初始呈现提交给屏幕之前运行,这将取消useEffect的资格,因为“传递给useEffect的函数将在将呈现提交给屏幕之后运行。”4。
因为我们想要保证代码只运行一次,这就使useMemo失去了资格,因为“在未来,React可能会选择“忘记”一些以前记住的值,并在下一次渲染时重新计算它们”5。
useState支持惰性初始状态计算,保证在初始渲染期间只运行一次,这似乎是一个很好的工作候选人。
useState的示例:
const runOnceBeforeRender = () => {};
const Component = () => {
useState(runOnceBeforeRender);
return (<></>);
}
作为自定义钩子:
const runOnceBeforeRender = () => {};
const useOnInitialRender = (fn) => {
useState(fn);
}
const Component = () => {
useOnInitialRender(runOnceBeforeRender);
return (<></>);
};
runOnceBeforeRender函数可以选择返回一个在函数第一次呈现时立即可用的状态,不会触发重新呈现。
一个(可能不必要的)NPM包:useOnce钩子
其他回答
我写了一个自定义钩子,它将在第一次渲染之前运行一个函数。
useBeforeFirstRender.js
import { useState, useEffect } from 'react'
export default (fun) => {
const [hasRendered, setHasRendered] = useState(false)
useEffect(() => setHasRendered(true), [hasRendered])
if (!hasRendered) {
fun()
}
}
用法:
import React, { useEffect } from 'react'
import useBeforeFirstRender from '../hooks/useBeforeFirstRender'
export default () => {
useBeforeFirstRender(() => {
console.log('Do stuff here')
})
return (
<div>
My component
</div>
)
}
根据reactjs.org的说法,componentWillMount在未来将不受支持。 https://reactjs.org/docs/react-component.html#unsafe_componentwillmount
不需要使用componentWillMount。
如果你想在组件挂载之前执行一些操作,只需在构造函数()中执行即可。
如果你想做网络请求,不要在componentWillMount中做。这是因为这样做会导致意想不到的错误。
网络请求可以在componentDidMount中完成。
希望能有所帮助。
2019年8月3日更新
你请求componentWillMount的原因可能是因为你想在呈现之前初始化状态。
就在我们的地盘上做吧。
const helloWorld=()=>{
const [value,setValue]=useState(0) //initialize your state here
return <p>{value}</p>
}
export default helloWorld;
或者你想在componentWillMount中运行一个函数,例如,如果你的原始代码看起来像这样:
componentWillMount(){
console.log('componentWillMount')
}
使用hook,你所需要做的就是删除生命周期方法:
const hookComponent=()=>{
console.log('componentWillMount')
return <p>you have transfered componeWillMount from class component into hook </p>
}
我只是想对第一个关于useEffect的答案补充一些东西。
useEffect(()=>{})
useEffect运行在每次渲染上,它是componentDidUpdate, componentDidMount和ComponentWillUnmount的组合。
useEffect(()=>{},[])
如果我们在useEffect中添加一个空数组,它只在组件挂载时运行。这是因为useEffect将比较您传递给它的数组。 所以它不一定是空数组。它可以是一个不变的数组。例如,它可以是[1,2,3]或['1,2']。useEffect仍然只在组件挂载时运行。
这取决于你是想让它只运行一次,还是在每次渲染后运行。如果您忘记添加数组,只要您知道自己在做什么,这并不危险。
我为hook创建了一个示例。请查看一下。
https://codesandbox.io/s/kw6xj153wr
2019年8月21日更新
我写上面的答案已经有一段时间了。有件事我觉得你需要注意。 当你使用
useEffect(()=>{},[])
当react比较传递给数组[]的值时,它使用Object.is()进行比较。 如果您将一个对象传递给它,例如
useEffect(()=>{},[{name:'Tom'}])
这和:
useEffect(()=>{})
每次都会重新呈现,因为object .is()比较对象时比较的是对象的引用,而不是值本身。这和为什么{}==={}返回false是一样的,因为它们的引用不同。 如果你仍然想比较对象本身而不是引用,你可以这样做:
useEffect(()=>{},[JSON.stringify({name:'Tom'})])
2021年7月9日更新:
关于依赖关系的一些更新:
一般来说,如果你使用一个函数或一个对象作为依赖项,它总是会重新呈现。但是react已经为您提供了解决方案:useCallback和useMemo
useCallback能够记住一个函数。 useMemo能够记住一个对象。
请看这篇文章:
https://javascript.plainenglish.io/5-useeffect-infinite-loop-patterns-2dc9d45a253f
你不能在钩子中使用任何现有的生命周期方法(componentDidMount, componentDidUpdate, componentWillUnmount等)。它们只能在类组件中使用。而Hooks只能用于功能组件。下面这句话来自React文档:
如果你熟悉React类的生命周期方法,你可以把useEffect Hook看作componentDidMount、componentDidUpdate和componentWillUnmount的组合。
建议是,可以在功能组件中从类组件中模拟这些生命周期方法。
componentDidMount中的代码在组件挂载时运行一次。useEffect钩子等价于此行为是
useEffect(() => {
// Your code here
}, []);
注意这里的第二个参数(空数组)。这将只运行一次。
如果没有第二个参数,useEffect钩子将在组件的每次渲染时被调用,这可能是危险的。
useEffect(() => {
// Your code here
});
componentWillUnmount用于清理(比如删除事件监听器,取消定时器等)。假设您正在componentDidMount中添加一个事件侦听器,并在componentWillUnmount中删除它,如下所示。
componentDidMount() {
window.addEventListener('mousemove', () => {})
}
componentWillUnmount() {
window.removeEventListener('mousemove', () => {})
}
与上述代码等价的钩子如下所示
useEffect(() => {
window.addEventListener('mousemove', () => {});
// returned function will be called on component unmount
return () => {
window.removeEventListener('mousemove', () => {})
}
}, [])
https://reactjs.org/docs/hooks-reference.html#usememo
记住,传递给useMemo的函数在呈现期间运行。 不要在那里做渲染时通常不会做的事情。 例如,副作用属于useEffect,而不是useMemo。
本·卡普的答案对我来说似乎是唯一有效的答案。
但由于我们使用的是函数式方法,另一种方法可以受益于闭包和HoC:
const InjectWillmount = function(Node, willMountCallback) {
let isCalled = true;
return function() {
if (isCalled) {
willMountCallback();
isCalled = false;
}
return Node;
};
};
然后使用它:
const YourNewComponent = InjectWillmount(<YourComponent />, () => {
console.log("your pre-mount logic here");
});