Javascript 如何在 React Hooks 中使用 componentWillMount()?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/53464595/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 05:07:13  来源:igfitidea点击:

How to use componentWillMount() in React Hooks?

javascriptreactjsjsxreact-hooks

提问by Abrar

In the official docs of React it mentions -

在 React 的官方文档中它提到 -

If you're familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.

如果您熟悉 React 类的生命周期方法,您可以将 useEffect Hook 视为 componentDidMount、componentDidUpdate 和 componentWillUnmount 的组合。

My question is - how can we use the componentWillMount()lifecyle method in a hook?

我的问题是 - 我们如何componentWillMount()在钩子中使用生命周期方法?

回答by Bhaskar Gyan Vardhan

You cannot use any of the existing lifecycle methods (componentDidMount, componentDidUpdate, componentWillUnmountetc.) in a hook. They can only be used in class components. And with Hooks you can only use in functional components. The line below comes from the React doc:

你不能使用任何现有的生命周期方法(componentDidMountcomponentDidUpdatecomponentWillUnmount在钩等)。它们只能在类组件中使用。使用 Hooks,您只能在功能组件中使用。下面这行来自 React 文档:

If you're familiar with React class lifecycle methods, you can think of useEffectHook as componentDidMount, componentDidUpdate, and componentWillUnmountcombined.

如果你熟悉阵营类生命周期方法,你能想到的useEffect钩。因为componentDidMountcomponentDidUpdatecomponentWillUnmount结合。

suggest is, you can mimic these lifecycle method from class component in a functional components.

建议是,您可以从功能组件中的类组件中模仿这些生命周期方法。

Code inside componentDidMountrun once when the component is mounted. useEffecthook equivalent for this behaviour is

componentDidMount安装组件时,内部代码运行一次。useEffect这种行为的钩子等价物是

useEffect(() => {
  // Your code here
}, []);

Notice the second parameter here (empty array). This will run only once.

注意这里的第二个参数(空数组)。这只会运行一次。

Without the second parameterthe useEffecthook will be called on every render of the component which can be dangerous.

如果没有第二个参数useEffect钩子将在组件的每个渲染上被调用,这可能是危险的。

useEffect(() => {
  // Your code here
});

componentWillUnmountis use for cleanup (like removing event listeners, cancel the timer etc). Say you are adding a event listener in componentDidMountand removing it in componentWillUnmountas below.

componentWillUnmount用于清理(如删除事件侦听器、取消计时器等)。假设您正在添加一个事件侦听器componentDidMount并将其删除,componentWillUnmount如下所示。

componentDidMount() {
  window.addEventListener('mousemove', () => {})
}

componentWillUnmount() {
  window.removeEventListener('mousemove', () => {})
}

Hook equivalent of above code will be as follows

相当于上面代码的钩子如下

useEffect(() => {
  window.addEventListener('mousemove', () => {});

  // returned function will be called on component unmount 
  return () => {
    window.removeEventListener('mousemove', () => {})
  }
}, [])

回答by MING WU

According to reactjs.org, componentWillMount will not be supported in the future. https://reactjs.org/docs/react-component.html#unsafe_componentwillmount

根据 reactjs.org,将来将不支持 componentWillMount。 https://reactjs.org/docs/react-component.html#unsafe_componentwillmount

There is no need to use componentWillMount.

无需使用 componentWillMount。

If you want to do something before the component mounted, just do it in the constructor().

如果你想在组件挂载之前做一些事情,只需在constructor()中做。

If you want to do network requests, do not do it in componentWillMount. It is because doing this will lead to unexpected bugs.

如果要做网络请求,就不要在componentWillMount里做。这是因为这样做会导致意想不到的错误。

Network requests can be done in componentDidMount.

网络请求可以在 componentDidMount 中完成。

Hope it helps.

希望能帮助到你。



updated on 08/03/2019

更新于 08/03/2019

The reason why you ask for componentWillMount is probably because you want to initialize the state before renders.

你要求 componentWillMount 的原因可能是因为你想在渲染之前初始化状态。

Just do it in useState.

只需在 useState 中执行即可。

const helloWorld=()=>{
    const [value,setValue]=useState(0) //initialize your state here
    return <p>{value}</p>
}
export default helloWorld;

or maybe You want to run a function in componentWillMount, for example, if your original code looks like this:

或者您可能想在 componentWillMount 中运行一个函数,例如,如果您的原始代码如下所示:

componentWillMount(){
  console.log('componentWillMount')
}

with hook, all you need to do is to remove the lifecycle method:

使用钩子,您需要做的就是删除生命周期方法:

const hookComponent=()=>{
    console.log('componentWillMount')
    return <p>you have transfered componeWillMount from class component into hook </p>
}

I just want to add something to the first answer about useEffect.

我只想在关于 useEffect 的第一个答案中添加一些内容。

useEffect(()=>{})

useEffect runs on every render, it is a combination of componentDidUpdate, componentDidMount and ComponentWillUnmount.

useEffect 在每次渲染上运行,它是 componentDidUpdate、componentDidMount 和 ComponentWillUnmount 的组合。

 useEffect(()=>{},[])

If we add an empty array in useEffect it runs just when the component mounted. It is because useEffect will compare the array you passed to it. So it does not have to be an empty array.It can be array that is not changing. For example, it can be [1,2,3] or ['1,2']. useEffect still only runs when component mounted.

如果我们在 useEffect 中添加一个空数组,它只会在组件安装时运行。这是因为 useEffect 会比较你传递给它的数组。所以它不一定是一个空数组。它可以是没有变化的数组。例如,它可以是 [1,2,3] 或 ['1,2']。useEffect 仍然只在组件安装时运行。

It depends on you whether you want it to run just once or runs after every render. It is not dangerous if you forgot to add an array as long as you know what you are doing.

这取决于您是希望它只运行一次还是在每次渲染后运行。只要您知道自己在做什么,如果您忘记添加数组,这并不危险。

I created a sample for hook. Please check it out.

我为钩子创建了一个示例。请检查一下。

https://codesandbox.io/s/kw6xj153wr

https://codesandbox.io/s/kw6xj153wr



updated on 21/08/2019

21/08/2019 更新

It has been a white since I wrote the above answer. There is something that I think you need to pay attention to. When you use

自从我写了上面的答案以来,它一直是白色的。我认为你需要注意一些事情。当你使用

useEffect(()=>{},[])

When react compares the values you passed to the array [], it uses Object.is() to compare. If you pass a object to it, such as

当 react 比较你传递给数组 [] 的值时,它使用 Object.is() 进行比较。如果你传递一个对象给它,比如

useEffect(()=>{},[{name:'Tom'}])

This is exactly the same as:

这与以下内容完全相同:

useEffect(()=>{})

It will re-render every time because when Object.is() compares an object, it compares its reference not the value itself. It is the same as why {}==={} returns false because their references are different. If you still want to compare the object itself not the reference, you can do something like this:

每次都会重新渲染,因为当 Object.is() 比较一个对象时,它比较的是它的引用而不是值本身。这与 {}==={} 返回 false 的原因相同,因为它们的引用不同。如果您仍然想比较对象本身而不是引用,您可以执行以下操作:

useEffect(()=>{},[JSON.stringify({name:'Tom'})])

回答by Ben Carp

useComponentDidMount hook

useComponentDidMount 钩子

In most cases useComponentDidMountis the tool to use. It will run only once, after component has mounted(initial render).

大多数情况下useComponentDidMount是使用的工具。它只会在组件安装后(初始渲染)运行一次。

 const useComponentDidMount = func => useEffect(func, []);

useComponentWillMount

useComponentWillMount

It is important to note that in class components componentWillMountis considered legacy. If you need code to run only once before component has mounted, you can use the constructor. More about it here. Since functional component doesn't have the equivelant of a constructor, using a hook to run code only once before component mounts might make sense in certain cases. You can achieve it with a custom hook.

重要的是要注意,类中的组件componentWillMount被认为是遗留的。如果您需要在安装组件之前只运行一次代码,您可以使用构造函数。更多关于它在这里。由于功能组件没有构造函数的等效项,因此在某些情况下,在组件挂载之前使用钩子仅运行一次代码可能是有意义的。您可以使用自定义钩子来实现它。

const useComponentWillMount = func => {
  const willMount = useRef(true);

  if (willMount.current) {
    func();
  }

  willMount.current = false;
};

However, there is a pitfall. Don't use it to asynchronously set your state (e.x following a server request. As you might expect it to affect the initial rendering which it won't). Such cases should be handled with useComponentDidMount.

但是,有一个陷阱。不要使用它来异步设置您的状态(例如跟随服务器请求。正如您所期望的那样,它会影响它不会影响的初始渲染)。此类情况应与useComponentDidMount.

Demo

演示

const Component = (props) => {
  useComponentWillMount(() => console.log("Runs only once before component mounts"));
  useComponentDidMount(() => console.log("Runs only once after component mounts"));
  ...

  return (
    <div>{...}</div>
  );
}

Full Demo

完整演示

回答by rob2d

useLayoutEffectcould accomplish this with an empty set of observers ([]) if the functionality is actually similar to componentWillMount-- it will run before the first content gets to the DOM -- though there are actually two updates but they are synchronous before drawing to the screen.

useLayoutEffect可以用一组空观察员(中做到这一点[]),但该功能实际上是相似componentWillMount-第一内容获取到DOM之前,它将运行-虽然实际上有两个更新,但他们绘制到屏幕前同步。

for example:

例如:


function MyComponent({ ...andItsProps }) {
     useLayoutEffect(()=> {
          console.log('I am about to render!');
     },[]);

     return (<div>some content</div>);
}

The benefit over useStatewith an initializer/setter or useEffectis though it may compute a render pass, there are no actual re-renders to the DOM that a user will notice, and it is run beforethe first noticable render, which is not the case for useEffect. The downside is of course a slight delay in your first render since a check/update has to happen before painting to screen. It really does depend on your use-case, though.

useState使用初始化器/设置器的好处useEffect是,尽管它可以计算渲染过程,但用户不会注意到对 DOM 的实际重新渲染,并且它第一个显着的渲染之前运行,这不是这种情况useEffect. 缺点当然是第一次渲染会稍微延迟,因为在绘制到屏幕之前必须进行检查/更新。不过,这确实取决于您的用例。

I think personally, useMemois fine in some niche cases where you need to do something heavy -- as long as you keep in mind it is the exception vs the norm.

我个人认为,useMemo在某些需要做一些繁重事情的利基情况下是可以的——只要你记住这是例外而不是常态。

回答by Littletime

I wrote a custom hook that will run a function once before first render.

我写了一个自定义钩子,它将在第一次渲染之前运行一次函数。

useBeforeFirstRender.js

useBeforeFirstRender.js

import { useState, useEffect } from 'react'

export default (fun) => {
  const [hasRendered, setHasRendered] = useState(false)

  useEffect(() => setHasRendered(true), [hasRendered])

  if (!hasRendered) {
    fun()
  }
}

Usage:

用法:

import React, { useEffect } from 'react'
import useBeforeFirstRender from '../hooks/useBeforeFirstRender'


export default () => { 
  useBeforeFirstRender(() => {
    console.log('Do stuff here')
  })

  return (
    <div>
      My component
    </div>
  )
}

回答by Jiri Mihal

This is the way how I simulate constructor in functional components using the useRefhook:

这是我如何使用useRef钩子在功能组件中模拟构造函数的方式:

function Component(props) {
    const willMount = useRef(true);
    if (willMount.current) {
        console.log('This runs only once before rendering the component.');
        willMount.current = false;        
    }

    return (<h1>Meow world!</h1>);
}

Here is the lifecycle example:

这是生命周期示例:

function RenderLog(props) {
    console.log('Render log: ' + props.children);
    return (<>{props.children}</>);
}

function Component(props) {

    console.log('Body');
    const [count, setCount] = useState(0);
    const willMount = useRef(true);

    if (willMount.current) {
        console.log('First time load (it runs only once)');
        setCount(2);
        willMount.current = false;
    } else {
        console.log('Repeated load');
    }

    useEffect(() => {
        console.log('Component did mount (it runs only once)');
        return () => console.log('Component will unmount');
    }, []);

    useEffect(() => {
        console.log('Component did update');
    });

    useEffect(() => {
        console.log('Component will receive props');
    }, [count]);


    return (
        <>
        <h1>{count}</h1>
        <RenderLog>{count}</RenderLog>
        </>
    );
}
[Log] Body
[Log] First time load (it runs only once)
[Log] Body
[Log] Repeated load
[Log] Render log: 2
[Log] Component did mount (it runs only once)
[Log] Component did update
[Log] Component will receive props

Of course Class components don't have Bodysteps, it's not possible to make 1:1 simulation due to different concepts of functions and classes.

当然Class组件没有Body步骤,由于函数和类的概念不同,无法进行1:1的模拟。

回答by AfikDeri

There is a nice workaround to implement componentDidMountand componentWillUnmountwith useEffect.

有一个很好的解决方法来实现componentDidMountcomponentWillUnmount使用useEffect.

Based on the documentation, useEffectcan return a "cleanup" function. this function will not be invoked on the first useEffectcall, only on subsequent calls.

根据文档,useEffect可以返回一个“清理”函数。此函数不会在第一次useEffect调用时调用,只会在后续调用中调用。

Therefore, if we use the useEffecthook with no dependencies at all, the hook will be called only when the component is mounted and the "cleanup" function is called when the component is unmounted.

因此,如果我们使用useEffect完全没有依赖关系的钩子,则只有在挂载组件时才会调用该钩子,并在卸载组件时调用“cleanup”函数。

useEffect(() => {
    console.log('componentDidMount');

    return () => {
        console.log('componentWillUnmount');
    };
}, []);

The cleanup return function call is invoked only when the component is unmounted.

仅在卸载组件时调用清理返回函数调用。

Hope this helps.

希望这可以帮助。

回答by Kerem atam

Ben Carp's answer seems like only valid one to me.

Ben Carp 的回答对我来说似乎只有一个。

But since we are using functional ways just another approach can be benefiting from closure and HoC:

但是由于我们使用的是函数式方式,所以另一种方法可以从闭包和 HoC 中受益:

const InjectWillmount = function(Node, willMountCallback) {
  let isCalled = true;
  return function() {
    if (isCalled) {
      willMountCallback();
      isCalled = false;
    }
    return Node;
  };
};

Then use it :

然后使用它:

const YourNewComponent = InjectWillmount(<YourComponent />, () => {
  console.log("your pre-mount logic here");
});

回答by ford04

Short answer to your originalquestion, how componentWillMountcan be used with React Hooks:

原始问题的简短回答,如何componentWillMount与 React Hooks 一起使用:

componentWillMountis deprecated and considered legacy. React recommendation:

componentWillMount弃用并被视为遗留。反应建议

Generally, we recommend using the constructor() instead for initializing state.

通常,我们建议使用 constructor() 代替初始化状态。

Now in the Hook FAQyou find out, what the equivalent of a class constructor for function components is:

现在在Hook FAQ 中你会发现,函数组件的类构造函数的等价物是什么:

constructor: Function components don't need a constructor. You can initialize the state in the useState call. If computing the initial state is expensive, you can pass a function to useState.

构造函数:函数组件不需要构造函数。您可以在 useState 调用中初始化状态。如果计算初始状态很昂贵,您可以将函数传递给 useState。

So a usage example of componentWillMountlooks like this:

所以一个使用示例componentWillMount如下所示:

const MyComp = () => {
  const [state, setState] = useState(42) // set initial value directly in useState 
  const [state2, setState2] = useState(createInitVal) // call complex computation

  return <div>{state},{state2}</div>
};

const createInitVal = () => { /* ... complex computation or other logic */ return 42; };

回答by ford04

https://reactjs.org/docs/hooks-reference.html#usememo

https://reactjs.org/docs/hooks-reference.html#usememo

Remember that the function passed to useMemo runs during rendering. Don't do anything there that you wouldn't normally do while rendering. For example, side effects belong in useEffect, not useMemo.

请记住,传递给 useMemo 的函数在渲染期间运行。不要在那里做任何你在渲染时通常不会做的事情。比如副作用属于useEffect,而不是useMemo。