React-hooks. Can't perform a React state update on an unmounted component

前端 未结 3 2017
孤独总比滥情好
孤独总比滥情好 2020-12-01 02:11

I get this error:

Can\'t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application

相关标签:
3条回答
  • 2020-12-01 02:39

    The easiest solution is to use a local variable that keeps track of whether the component is mounted or not. This is a common pattern with the class based approach. Here is an example that implement it with hooks:

    function Example() {
      const [text, setText] = React.useState("waiting...");
    
      React.useEffect(() => {
        let isCancelled = false;
    
        simulateSlowNetworkRequest().then(() => {
          if (!isCancelled) {
            setText("done!");
          }
        });
    
        return () => {
          isCancelled = true;
        };
      }, []);
    
      return <h2>{text}</h2>;
    }
    

    Here is an alternative with useRef (see below). Note that with a list of dependencies this solution won't work. The value of the ref will stay true after the first render. In that case the first solution is more appropriate.

    function Example() {
      const isCancelled = React.useRef(false);
      const [text, setText] = React.useState("waiting...");
    
      React.useEffect(() => {
        fetch();
    
        return () => {
          isCancelled.current = true;
        };
      }, []);
    
      function fetch() {
        simulateSlowNetworkRequest().then(() => {
          if (!isCancelled.current) {
            setText("done!");
          }
        });
      }
    
      return <h2>{text}</h2>;
    }
    

    You can find more information about this pattern inside this article. Here is an issue inside the React project on GitHub that showcase this solution.

    0 讨论(0)
  • 2020-12-01 02:39

    TL;DR

    Here is a CodeSandBox example

    The other answers work of course, I just wanted to share a solution I came up with. I built this hook that works just like React's useState, but will only setState if the component is mounted. I find it more elegant because you don't have to mess arround with an isMounted variable in your component !

    Installation :

    npm install use-state-if-mounted
    

    Usage :

    const [count, setCount] = useStateIfMounted(0);
    

    You can find more advanced documentation on the npm page of the hook.

    0 讨论(0)
  • 2020-12-01 02:48

    If you are fetching data from axios(using hooks) and the error still occurs, just wrap the setter inside the condition

    let isRendered = useRef(false);
    useEffect(() => {
        isRendered = true;
        axios
            .get("/sample/api")
            .then(res => {
                if (isRendered) {
                    setState(res.data);
                }
                return null;
            })
            .catch(err => console.log(err));
        return () => {
            isRendered = false;
        };
    }, []);
    
    0 讨论(0)
提交回复
热议问题