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

发布时间:2021-06-26 13:52:38 作者:chen
来源:亿速云 阅读:235

本篇内容主要讲解“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],我们可以通过在文件中添加以下注释来解决这个问题。

/* @refresh reset */

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

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

推荐阅读:
  1. 如何优雅的使用react hooks来进行状态管理
  2. React中Hooks的示例分析

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

react hooks react

上一篇:基于vue2.0如何实现仿百度前端分页效果

下一篇:Vue商品控件与购物车联动效果怎么实现

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》