React18中useEffect执行两次
什么是严格模式
strict mode就是一个工具,用来检查应用中可能存在的问题。 严格模式只会在生产环境下运行,在开发环境下它是没有影响的。import React from "react"; function ExampleApplication() { return ( ); } 复制代码
你可以用React.StrictMode包裹你想要检查的应用,没有包裹的应用是不会受到影响的。比如上述的代码中组件是不会受到严格模式的作用的,只有我们包裹的和才会受到严格模式的影响。严格模式的作用
严格模式会进行如下的检查识别不安全的生命周期,比如componentWillMount。后面升级成了componentDidMount
对ref这个API以前版本的检查,希望你换成新的版本findDOMNode被弃用的警告检测意外的副作用发现context过期的API确保可重复使用的stateReact官方文档中给出了一个例子,意思应该是说如果我们从路由A跳转到路由B,再从路由B返回去的时候。 React希望立即展示原来的状态,也就我可以把A的状态缓存起来,那么我们返回的时候就可以根据缓存中的状态立刻渲染出来。 复制代码为什么React将useEffect设置为执行两次
刚刚我们提到,React 将支持使用卸载前已有的组件状态重新挂载到树上。但需要组件对多次挂载和销毁的副作用具有弹性。这里需要我们好好理解React中的副作用,笔者也还没有完全理解这句话的意思,但是我们可以根据React官方文档给出的例子来好好理解useEffect的使用场景,然后再回来理解这句话表达的含义。
意思好像是如果React不将Effect设置成执行两次,那么React在做这方面优化的时候可能会引发一些问题。并且这些问题并不会让开发者注意到,所以React将Effect设置成执行两次,就是为了让问题提前暴露出来。React还认为Effect执行两次在大部分情况下是没有问题的
非严格模式* React mounts the component. //挂载组件 * Layout effects are created. //layout执行 * Effects are created. //Effects执行 复制代码
严格模式* React mounts the component. //挂载组件 * Layout effects are created. //layout执行 * Effect effects are created. // Effects执行 * React simulates effects being destroyed on a mounted component. //React模拟组件销毁 * Layout effects are destroyed. // layout销毁 * Effects are destroyed. // Effects销毁 * React simulates effects being re-created on a mounted component. // React模拟重新挂载 * Layout effects are created // layout重新创建 * Effect setup code runs // Effect重新执行 复制代码如何在应用中处理Effect执行两次的问题
React认为执行两次在大多数情况下并没有有什么影响,我们应该考虑的是在重新挂载之后,如何让Effect正确的执行,而不是怎么才能让Effect执行一次。下面我们看些优化的场景。请求数据
我们可以通过一个变量来控制请求的时候只发出去一次,也可以通过取消请求的方式来进行改善。useEffect(() => { let ignore = false; async function startFetching() { const json = await fetchTodos(userId); if (!ignore) { setTodos(json); } } startFetching(); return () => { ignore = true; }; }, [userId]); 复制代码弹窗问题
在第二次挂载之前,将弹窗close掉,就不会有两次调用showModal()的问题了useEffect(() => { const dialog = dialogRef.current; dialog.showModal(); return () => dialog.close(); }, []); 复制代码Not an Effect: Buying a product
不知道标题怎么翻译比较合适,直接拿过来用吧useEffect(() => { fetch("/api/buy", { method: "POST" }); }, []); 复制代码
React认为在useEffect里面发送post请求是不正确的,这种需求场景是不存在的。你应该是在点击事件中发送某个post请求,而不是直接在useEffect里面。setTimeout
记得在useEffect里面取消定时器 useEffect(() => { function onTimeout() { console.log(" " + text); } console.log(" Schedule "" + text + "" log"); const timeoutId = setTimeout(onTimeout, 3000); return () => { console.log(" Cancel "" + text + "" log"); clearTimeout(timeoutId); }; }, [text]);