理解React hook 之 useMemo

338 阅读3分钟

前言

在react众多hook当中,useMemo也是很基础的一个钩子,这个钩子侧重点在于优化性能,在我理解来有点类似于vue的计算属性computed,今天为了加深印象让自己学的更深刻,就在这里写下自己对useMemo的一点理解。

这里首先贴下代码,然后枚举代码逐行理解。

type User = {
  name: String;
  age: number;
};

const Home: React.FC = () => {
  const [name, setName] = useState<String>("");
  const [user, setUser] = useState<User>({} as User);

  const resUser = () => {
    console.log("获取到了user");
    return user;
  };

  const getUser = useMemo(resUser, [name]);

  const setUserInfo = () => {
    setName("jack");
    setUser({ name: "jack", age: 26 });
  };

  return (
    <div className="Home">
      <Button type="primary" onClick={setUserInfo}>
        memo
      </Button>
      <p>这里是:{getUser.name || "无"}</p>
    </div>
  );
};

分析

  • 定义了User类型,分别包含name和age属性
  • 函数式组件声明一个Home组件
  • 定义两个state,一个是名字相关的state,一个是user信息相关的state
  • 首先观察组件返回的HTML内容,包含一个Button 和<p>标签。其中<p>标签包含了getUser方法,而getUser则是用useMemo进行缓存resUser这个方法,从而返回这个方法中的值。可以看出,返回的值是个User类型的对象。但是一开始user默认是{}空对象,所以<p>元素的内容就是:“这里是:无”。紧接着useMemo的第二个参数是更新依赖的数组,这里只放入了一个name,意思是只要name这个state发生了变化,就会触发resUser这个方法,从而返回新的user对象。
  • 其次有个Button组件,点击事件是setUserInfo,这个方法做了两件事:一是更新了名称,二是更新了user对象。而正是因为更新了name,所以会触发useMemo缓存的方法,即会重新执行resUser拿到最新的user对象,而刚好再setUserInfo中更新了user对象,所以resUser也返回了最新的user。此时的<p>元素的内容就是:“这里是:Jack”

到这里整个代码分析完了。

但是如果我们把setUserInfo这个方法中的setName("jack");这行代码去掉,也就是不更新名字了。还会出发resUser这个方法吗?答案肯定是不行的。因为useMemo的依赖更新就是name发生了改变才会触发相对应的方法。

这样做的好处

要想知道这样做的好处,那我们就写个不用useMemo可以实现的代码,改一下Home组件代码:

const Home: React.FC = () => {
  const [user, setUser] = useState<User>({} as User);

  const setUserInfo = () => {
    setUser({ name: "jack", age: 26 });
  };
  const resUser = () => {
      // ... other operate
    return user;
  };
  const updateOther = () = > {
      // ... other state updated
  }

  return (
    <div className="Home">
      <Button type="primary" onClick={setUserInfo}>
        memo
      </Button>
      <p>这里是:{resUser().name || "无"}</p>
      <Button type="primary" onClick={updateOther}>
        update other
      </Button>
    </div>
  );
};

比如像上面这种在Html里面引用方法。当你点击updateOther这个事件更新了其他的state会重新渲染这个组件的时候,resUser 这个方法会再次进入。如果遇到了复杂的逻辑,这对性能上是非常不友好的,明明没有改变关于user的state,却重新去获取user信息,这种消耗一定要避免。

所以用了useMemo之后,它所包含的方法必须依赖某个更新的项才能再次执行,否则就读取上一次缓存的值。这就是useMemo在优化性能上的好处。

最后

本文所列举的例子可能不是很恰当,明明有更简单的方法可以实现的。一样性能也更好。但笔者写这篇技术贴只是加强自己对react hook的理解。只要理解了能更好的运用到项目中就很好了。当然这也是笔者自己一点点拙劣的劣迹,后续有更深的理解会再次更新。