文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

React Hooks在React-refresh模块热替换下的异常行为怎么解决

2024-04-02 19:55

关注

本篇内容主要讲解“React Hooks在React-refresh模块热替换下的异常行为怎么解决”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“React Hooks在React-refresh模块热替换下的异常行为怎么解决”吧!

 什么是 react-refresh

react-refresh-webpack-plugin[1] 是 React 官方提供的一个 模块热替换(HMR)插件。

在开发环境编辑代码时,react-refresh 可以保持组件当前状态,仅仅变更编辑的部分。在 umi[2] 中可以通过 fastRefresh:  {}快速开启该功能。

React Hooks在React-refresh模块热替换下的异常行为怎么解决

这张 gif 动图展示的是使用 react-refresh  特性的开发体验,可以看出,修改组件代码后,已经填写的用户名和密码保持不变,仅仅只有编辑的部分变更了。

react-refresh 的简单原理

对于 Class 类组件,react-refresh 会一律重新刷新(remount),已有的 state  会被重置。而对于函数组件,react-refresh 则会保留已有的 state。所以 react-refresh 对函数类组件体验会更好。本篇文章主要讲解  React Hooks 在 react-refresh 模式下的怪异行为,现在我来看下 react-refresh 对函数组件的工作机制。

在热更新时为了保持状态,useState 和 useRef 的值不会更新。

在热更新时,为了解决某些问题[3],useEffect、useCallback、useMemo 等会重新执行。

React Hooks在React-refresh模块热替换下的异常行为怎么解决

如上图所示,在文本修改之后,state保持不变,useEffect被重新执行了。

react-refresh 工作机制导致的问题

在上述工作机制下,会带来很多问题,接下来我会举几个具体的例子。

第一个问题

import React, { useEffect, useState } from 'react';  export default () => {   const [count, setState] = useState(0);    useEffect(() => {     setState(s => s + 1);   }, []);    return (     <div>       {count}     </div>   ) }

上面的代码很简单,在正常模式下,count值最大为 1。因为 useEffect 只会在初始化的时候执行一次。但在 react-refresh  模式下,每次热更新的时候,state 不变,但 useEffect 重新执行,就会导致 count 的值一直在递增。

React Hooks在React-refresh模块热替换下的异常行为怎么解决

如上图所示,count 随着每一次热更新在递增。

第二个问题

如果你使用了 ahooks[4] 或者 react-use[5] 的 useUpdateEffect,在热更新模式下也会有不符合预期的行为。

import React, { useEffect } from 'react'; import useUpdateEffect from './useUpdateEffect';  export default () => {    useEffect(() => {     console.log('执行了 useEffect');   }, []);    useUpdateEffect(() => {     console.log('执行了 useUpdateEffect');   }, []);    return (     <div>       hello world     </div>   ) }

useUpdateEffect 与 useEffect相比,它会忽略第一次执行,只有在 deps  变化时才会执行。以上代码的在正常模式下,useUpdateEffect 是永远不会执行的,因为 deps 是空数组,永远不会变化。但在  react-refresh 模式下,热更新时,useUpdateEffect 和 useEffect 同时执行了。

React Hooks在React-refresh模块热替换下的异常行为怎么解决

造成这个问题的原因,就是 useUpdateEffect 用 ref 来记录了当前是不是第一次执行,见下面的代码。

import { useEffect, useRef } from 'react';  const useUpdateEffect: typeof useEffect = (effect, deps) => {   const isMounted = useRef(false);    useEffect(() => {     if (!isMounted.current) {       isMounted.current = true;     } else {       return effect();     }   }, deps); };  export default useUpdateEffect;

上面代码的关键在 isMounted

初始化时,useEffect 执行,标记 isMounted 为 true

热更新后,useEffect 重新执行了,此时 isMounted 为 true,就往下执行了

第三个问题

最初发现这个问题,是 ahooks 的 useRequest 在热更新后,loading 会一直为 true。经过分析,原因就是使用 isUnmount  ref 来标记组件是否卸载。

import React, { useEffect, useState } from 'react';  function getUsername() {   console.log('请求了')   return new Promise(resolve => {     setTimeout(() => {       resolve('test');     }, 1000);   }); }  export default function IndexPage() {    const isUnmount = React.useRef(false);   const [loading, setLoading] = useState(true);    useEffect(() => {     setLoading(true);     getUsername().then(() => {       if (isUnmount.current === false) {         setLoading(false);       }     });     return () => {       isUnmount.current = true;     }   }, []);    return loading ? <div>loading</div> : <div>hello world</div>; }

如上代码所示,在热更新时,isUnmount 变为了true,导致二次执行时,代码以为组件已经卸载了,不再响应异步操作。

如何解决这些问题

方案一

第一个解决方案是从代码层面解决,也就是要求我们在写代码的时候,时时能想起来 react-refresh 模式下的怪异行为。比如  useUpdateEffect 我们就可以在初始化或者热替换时,将 isMounted ref 初始化掉。如下:

import { useEffect, useRef } from 'react';  const useUpdateEffect: typeof useEffect = (effect, deps) => {   const isMounted = useRef(false);  +  useEffect(() => { +   isMounted.current = false; +  }, []);      useEffect(() => {     if (!isMounted.current) {       isMounted.current = true;     } else {       return effect();     }   }, deps); };  export default useUpdateEffect;

这个方案对上面的问题二和三都是有效的。

方案二

根据官方文档[6],我们可以通过在文件中添加以下注释来解决这个问题。

添加这个问题后,每次热更新,都会 remount,也就是组件重新执行。useState 和 useRef 也会重置掉,也就不会出现上面的问题了。

到此,相信大家对“React Hooks在React-refresh模块热替换下的异常行为怎么解决”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯