反应使用效果挂钩清理

时间:2020-09-08 19:50:36

标签: javascript reactjs api react-hooks use-effect

我试图了解使用useEffect清理的确切反应以及用于什么目的。您能否通过添加清理来帮助我修复代码

据我所知

在关闭订阅的API调用中使用了它。仍然无法弄清其使用原因以及使用方法。

useEffect(() => {
        async function onLoad() {
        
            try {
              
              const examSessions = await loadSessions(id);
              setSessions(examSessions);
              console.log(`examSession`,examSessions)
            } catch (e) {
            //   onError(e);
                console.log(e)
            }
        
            setIsLoading(false);
        }


        onLoad()
    }, [id])



    function loadSessions(id) {
        const result = API.get("vce", `/session/${id}`)
        return result
    }

2 个答案:

答案 0 :(得分:1)

如果不进行清理,即使已卸载组件,效果也将永远做下去。

这对于可能负责设置网络事物(例如Web套接字连接)或使用fetch请求数据的复杂组件很重要。如果您没有取消或关闭这些资源,这些资源将仍然处于打开状态并可能发送信号。

考虑以下示例,我们可以在其中切换选中的Foo组件。清理掉注释后,即使它已卸载,我们仍会看到“ Tick”,因为我们没有时间清理间隔。

实际上,如果重新切换Foo,您将开始在控制台中看到更多的“滴答”,因为现在有2个以上的滴答声。假设这是一个Web套接字,并且每次重新安装时我们都在计划一个新的心跳信号;服务器会对我们的应用心跳感到非常生气。

const {
  useState,
  useEffect,
  createElement
} = React;
const {
  render
} = ReactDOM;

const Foo = () => {
  const [t, setT] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      console.log("Tick");
      setT(currT => currT + 1);
    }, 1000);

    // Without the following, you will see "Tick" forever because it isn't cleaned up
    //return () => clearInterval(interval);

  }, []);

  return createElement("div", {}, t);
};

const App = () => {
  const [should, setShould] = useState(true);

  return createElement("div", null, 
    createElement("button", {
      onClick: () => setShould(currShould => !currShould)
    }, "toggle"),
    should ? createElement(Foo) : null
  );
};

render(
  createElement(App),
  document.getElementById('app')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="app"></div>

将以下示例与 具有以下清理操作的示例进行比较: 您可以切换Foo组件。

const {
  useState,
  useEffect,
  createElement
} = React;
const {
  render
} = ReactDOM;

const Foo = () => {
  const [t, setT] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      console.log("Tick");
      setT(currT => currT + 1);
    }, 1000);

    // Without the following, you will see "Tick" forever because it isn't cleaned up
    return () => clearInterval(interval);

  }, []);

  return createElement("div", {}, t);
};

const App = () => {
  const [should, setShould] = useState(true);

  return createElement("div", null, 
    createElement("button", {
      onClick: () => setShould(currShould => !currShould)
    }, "toggle"),
    should ? createElement(Foo) : null
  );
};

render(
  createElement(App),
  document.getElementById('app')
);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="app"></div>

答案 1 :(得分:0)

您无需在此处使用清理挂钩。您尚未订阅任何内容。当您对某个内容使用useEffect订阅并且不取消订阅组件破坏时,此订阅将继续侦听远程源,窃取设备内存和用户数据。

要对其进行测试,您只需在按钮上附加一个单击侦听器,安装/卸载组件(无需刷新页面),然后在chrome dev工具中查看订阅/侦听器列表的增长方式即可。

编辑: 试试这个

useEffect(() => {
        let unmounted = false;
        async function onLoad() {
        
            try {
              
              const examSessions = await loadSessions(id);
              setSessions(examSessions);
              console.log(`examSession`,examSessions)
            } catch (e) {
            //   onError(e);
                console.log(e)
            }
        
            if(!unmounted)setIsLoading(false);
        }


        onLoad()
        return ()=> unmounted = true;
    }, [id])