IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> `useEffect`触发两次引起的bug -> 正文阅读

[JavaScript知识库]`useEffect`触发两次引起的bug

写在前面

今天在用react+typescripttodolist的时候出现了一个奇怪的bug。那就是…

useEffect执行了两次

useEffect(()=>{

},[])
  • 一般来说,第二个参数给一个空数组,useEffect只会执行一次的
  • 有图有真相!

在这里插入图片描述

  • 在研究这个问题后得到了大概三种解决方案:
    • 1.取消react.strictMode模式
    • 2.在设置的参数的useEffect中加非空判断
    • 3.把初始化放到useReducer里面

具体的分析在下面可以看到

程序源码

  • 因为不是全部源码,下面的解说会帮你理解代码
    • 1.init()是useReducer的第三个参数
    • 2.[state,dispatch]是用来控制todoList的相关操作的(这个不是本文重点)
    • 3.第一个useEffect就是第一次进入页面读取localStorage的数据赋值给state.todoList
    • 4.第二个useEffectstate.todoList变化后把它存储在localStorage里面
  function init(initTodoList: ITodo[]): IState {
    return {
      todoList: initTodoList
    }
  }
  const [state, dispatch] = useReducer(todoReducer, [], init)
  useEffect(() => {
    const todoList = JSON.parse(localStorage.getItem('todolist') ?? '[]')
    console.log(todoList, 'useEffect')
    dispatch({
      type: ACTION_TYPE.INIT_TODOLIST,
      payload: todoList
    })
  }, [])
  useEffect(() => {
    localStorage.setItem('todolist', JSON.stringify(state.todoList))
  }, [state.todoList])

出错原因分析

  • 错误图解如下
    在这里插入图片描述

strictMode导致组件两次加载

  • React18添加了strictModenpx create-react-app创建新项目默认是带有strictMode严格模式的
    • 这个模式会导致组件加载两次,如果我们关闭掉这个模式,就不会出错了
    • 但是这并没有根除我们的bug,因为正常加载两次也是不会出错的
    • 而且,退一步来说,新项目自带严格模式,说明它是有必要的,官网也提到了它的优点,这里不展开讨论了
const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>  // 这里
    <App />
  </React.StrictMode>
);

如果代码没有问题,加载两次应该是不会出错了,所以有了后面的解决办法的研究

第一次拿到了,第二次没拿到,说明第一次拿到后出了问题

  • 也就是第二次useEffect那里出的问题
    • 在第一个useEffect还没有完成初始化的时候,useReducer触发了第二个useEffect,导致了我们重新setItem导致了localStorage中的todolist变成了空数组
    • 自然在第二次取的时候就变成了空组数
    • 所以我们加一个判断,非空的时候再改变就可以了
      • 注意:这里的判断不能用state.todoList===[]
  useEffect(() => {
    if (state.todoList.length)
      localStorage.setItem('todolist', JSON.stringify(state.todoList))
  }, [state.todoList])

专业的把初始化放到useReducer里面

  • 就是直接绕开第一个Effect的取值
  const [state, dispatch] = useReducer(todoReducer, JSON.parse(localStorage.getItem('todolist') ?? '[]'), init)
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-06-08 18:57:17  更:2022-06-08 18:58:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 16:29:02-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码