React18 严格模式下的双重渲染之谜

文章目录

问题

这是一个 React Demo 项目 ,启动后在 Chrome 控制台里发现 控制台 被打印了 "两次",但是,在生产环境中,这个问题通常不会出现,所以可以主要关注开发环境中的行为。

javascript 复制代码
// 入口文件
import { StrictMode } from 'react';
import * as ReactDOMClient from 'react-dom/client';
import App from './App';
const root = ReactDOMClient.createRoot(document.getElementById('root'));
root.render(
  <StrictMode>
    <App />
  </StrictMode>
);
javascript 复制代码
// 组件代码
import React, { useEffect } from 'react';

const App = () => {
  useEffect(() => {
    console.log('组件挂载完成!');
  }, []);
  return <>Hello world!</>;
};

分析

  1. 这是 React18 才新增的特性。

  2. 仅在开发模式("development")下,且使用了严格模式("Strict Mode")下会触发。

    生产环境("production")模式下和原来一样,仅执行一次。

  3. 之所以执行两次,是为了模拟立即卸载组件和重新挂载组件。

    为了帮助开发者提前发现重复挂载造成的 Bug 的代码。

    同时,也是为了以后 React的新功能做铺垫。

    未来会给 React 增加一个特性,允许 React 在保留状态的同时,能够做到仅仅对UI部分的添加和删除。

    让开发者能够提前习惯和适应,做到组件的卸载和重新挂载之后, 重复执行 useEffect的时候不会影响应用正常运行。

  4. 每次组件渲染时,React 都会更新页面 UI,然后运行 useEffect 中的代码

  5. Effect 在屏幕更新之后的 rendering 进程结束的时候执行。

解决

方式一:使用状态标志

javascript 复制代码
const [isDataFetched, setIsDataFetched] = useState(false);

useEffect(() => {
  if (!isDataFetched) {
    getDataList();
    setIsDataFetched(true);
  }
}, [isDataFetched]);

方式二:使用 useRef

javascript 复制代码
const dataFetchedRef = useRef(false);

useEffect(() => {
  if (dataFetchedRef.current) return;
  dataFetchedRef.current = true;
  getDataList();
}, []);

方式三:移除严格模式

方式四:使用 useCallback

将 getDataList 函数用 useCallback 包裹,可以确保它的引用稳定性。

相关推荐
tianchang12 分钟前
JS 排序神器 sort 的正确打开方式
前端·javascript·算法
每一天,每一步37 分钟前
React页面使用ant design Spin加载遮罩指示符自定义成进度条的形式
前端·react.js·前端框架
做你的猫1 小时前
深入剖析:基于Vue 3与Three.js的3D知识图谱实现与优化
前端·javascript·vue.js
做你的猫1 小时前
深入剖析:基于Vue 3的高性能AI聊天组件设计与实现
前端·javascript·vue.js
dreams_dream2 小时前
vue2实现背景颜色渐变
前端·javascript·css
中微子2 小时前
🏆 ES6 异步编程挑战营:从入门到........
javascript
月弦笙音2 小时前
【XSS】后端服务已经加了放xss攻击,前端还需要加么?
前端·javascript·xss
code_Bo2 小时前
基于vueflow实现动态添加标记的装置图
前端·javascript·vue.js
渊不语4 小时前
PasteTextArea 智能文本域粘贴组件 - 完整实现指南
react.js
CodeTransfer4 小时前
css中animation与js的绑定原来还能这样玩。。。
前端·javascript