欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

React 小技巧教你如何摆脱hooks依赖烦恼

程序员文章站 2022-03-17 22:53:54
react项目中,很常见的一个场景:const [watchvalue, setwatchvalue] = usestate('');const [othervalue1, setothervalue...

react项目中,很常见的一个场景:

const [watchvalue, setwatchvalue] = usestate('');
const [othervalue1, setothervalue1] = usestate('');
const [othervalue2, setothervalue2] = usestate('');

useeffect(() => {
    dosomething(othervalue1, othervalue2);
}, [watchvalue, othervalue1, othervalue2]);

我们想要watchvalue改变的时候执行dosomething,里面会引用其他值othervalue1, othervalue2

这时有个让人烦恼的问题:

  • 如果不把othervalue1, othervalue2加入依赖数组的话,dosomething里面很可能会访问到othervalue1, othervalue2旧的变量引用,从而发生意想不到的错误(如果安装hooks相关eslint的话,会提示警告)。
  • 反之,如果把othervalue1, othervalue2加入依赖数组的话,这两个值改变的时候dosomething也会执行,这并不是我们想要的(我们只想引用他们的值,但不想它们触发dosomething)。

othervalue1, othervalue2变成ref可以解决这个问题:

const [watchvalue, setwatchvalue] = usestate('');
const other1 = useref('');
const other2 = useref('');

// ref可以不加入依赖数组,因为引用不变
useeffect(() => {
    dosomething(other1.current, other2.current);
}, [watchvalue]);

这样other1, other2的变量引用不会变,解决了前面的问题,但是又引入了一个新的问题:other1, other2的值current改变的时候,不会触发组件重新渲染(useref的current值改变不会触发组件渲染),从而值改变时候界面不会更新!

这就是hooks里面的一个头疼的地方,usestate变量会触发重新渲染、保持界面更新,但作为useeffect的依赖时,又总会触发不想要的函数执行。useref变量可以放心作为useeffect依赖,但是又不会触发组件渲染,界面不更新。
如何解决?

可以将userefusestate的特性结合起来,构造一个新的hooks函数: usestateref

import { usestate, useref } from "react";

// 使用 useref 的引用特质, 同时保持 usestate 的响应性
type staterefobj<t> = {
  _state: t;
  value: t;
};
export default function usestateref<t>(
  initialstate: t | (() => t)
): staterefobj<t> {
  // 初始化值
  const [init] = usestate(() => {
    if (typeof initialstate === "function") {
      return (initialstate as () => t)();
    }
    return initialstate;
  });
  // 设置一个 state,用来触发组件渲染
  const [, setstate] = usestate(init);
  
  // 读取value时,取到的是最新的值
  // 设置value时,会触发setstate,组件渲染
  const [ref] = usestate<staterefobj<t>>(() => {
    return {
      _state: init,
      set value(v: t) {
        this._state = v;
        setstate(v);
      },
      get value() {
        return this._state;
      },
    };
  });
  
  // 返回的是一个引用变量,整个组件生命周期之间不变
  return ref;
}

这样,我们就能这样用:

const watch = usestateref('');
const other1 = usestateref('');
const other2 = usestateref('');

// 这样改变值:watch.value = "new";

useeffect(() => {
    dosomething(other1.value, other2.value);
   // 其实现在这三个值都是引用变量,整个组件生命周期之间不变,完全可以不用加入依赖数组
   // 但是react hooks的eslint插件只能识别useref作为引用,不加人会警告,为了变量引用安全还是加入
}, [watch.value, other1, other2]);

这样,watch, other1,other2useref的引用特性,不会触发dosomething不必要的执行。又有了usestate的响应特性,改变.value的时候会触发组件渲染和界面更新。
我们想要变量改变触发dosomething的时候,就把watch.value加入依赖数组。我们只想引用值而不想其触发dosomething的时候,就把变量本身加入数组。

以上就是react 小技巧教你如何摆脱hooks依赖烦恼的详细内容,更多关于react hooks依赖的资料请关注其它相关文章!