我们相信:世界是美好的,你是我也是。平行空间的世界里面,不同版本的生活也在继续...

本文说一下React的自定义钩子useReactive()的实现和应用方法,它来自ahooks这个著名的react hooks库。它对标的是react官方的useState()。当然,也不能说useReactive()钩子就一定比useState()钩子先进,两者各有所长。

苏南大叔:React自定义hook,ahooks的useReactive响应式变量管理 - useReactive响应式变量
React自定义hook,ahooks的useReactive响应式变量管理(图3-1)

苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0create-react-app@5.0.1react-router-dom@6.27.0react@18.3.1ahooks@3.8.1。当然,网络上也流传着多个版本的useReactive(),本文描述的来自ahooks

响应的方式

useReactive()useState()的最大区分点就是:响应的方式不同。

  • useReactive()里面的写法,更符合大家传统的代码思路。变量修改设置后立刻生效,立刻自动更新界面。技术流派。
  • useState()里面的写法,稍稍的显得不那么智能一点。变量被修改后,并不是立即就生效的,会在稍后的某个时机才会生效,略显迟钝,不够“响应式”。但是,useState()里面的各种缓存优化逻辑,就建立在这个“略显迟钝”上。大智若愚。

“响应式”的概念,举例如下:

import { useState } from "react";
function App() {
  let sunan = "苏南大哥";                   // 普通变量
  const [sn, setSn] = useState("苏南大叔"); // react托管
  const test = () => {
    sunan = "sunan大哥";
    setSn("sunan大叔");
    // alert(sunan);
  };
  return (
    <div className="App">
      {sunan}[普通变量][不会变化]<br/>
      {sn}[react托管][会变化]<br/>
      <button onClick={test}>修改变量</button>
    </div>
  );
}
export default App;

这里普通的变量sunan,虽然确实变化了。但不会引起界面的更新,不够“响应式”。
reactuseState接管的变量sn,通过setSn()修改后,会“立即”更新界面,这个够“响应式”。(但是,这个时候,普通的变量引用,仍然不会变化)

useReactive()例子

useReactive()useState()的区别:

  • useReactive()管理的是一个状态(state)集合,state是个类对象的实例。直接修改这个对象,就可以做到界面刷新。
  • useState()管理的是一个个碎片化的变量,并不集中到一起。界面更新依赖于【更新函数】的执行,而不是自然对变量的修改。
换句话说,useReactive()能做到,既符合传统的变量更改习惯,又符合react界面及时响应的要求。
npm i ahooks --save

最简单的例子:

import React from "react";
import useReactive from "./useReactive.js";
function App() {
  const state = useReactive({
    name: "苏南大叔",
    family: ["苏南", "大叔", "苏南大叔"],
    get title() {
      return "京城非著名互联网从业人员," + this.name;
    },
    rename(_name) {
      this.name = _name;
    },
  });
  const test = () => {
    state.name = "sunan大叔";
  };
  const test2 = (_name) => {
    state.rename(_name);
    state.family.push(_name);
  };
  return (
    <div className="App">
      {state.name}
      <br />
      {state.title}
      <br />
      <button onClick={test}>修改变量</button>
      <button onClick={test2.bind(this, "sunan大哥")}>修改变量2</button><br />
      {JSON.stringify(state.bugs)}
      <ul>
        {state.family.map((bug, index) => {
          return <li key={index}>{bug}</li>;
        })}
      </ul>
    </div>
  );
}
export default App;

苏南大叔:React自定义hook,ahooks的useReactive响应式变量管理 - useReactive
React自定义hook,ahooks的useReactive响应式变量管理(图3-2)

useReactive()管理的数据

useReactive()管理的数据,实际上是个类的实例。

{
  name: "苏南大叔",
  get title() {
    return "京城非著名互联网从业人员," + this.name;
  },
  rename(_name) {
    this.name = _name;
  },
}

这里的rename(_name){}也可以写成rename:function(_name){},但是如果写成匿名函数的话rename:(_name)=>{},就会丧失this.的正确访问。

使用场景区分

苏南大叔认为:

  • 片段化的普通变量(不能是object)管理,使用useState()
  • 对象object的数据集中管理,可以使用useReactive()
  • 多组件,更统一的数据访问,可以使用useContext()
  • 更加复杂,甚至超越react范畴的操作,请使用reduxuseSelector()

更新方式区别

useReactive()的操作对象,是个类的实例{}。使用方式上,就是在定义的时候,多了个useReactive({})字样,其它的地方,和普通的jsreact相比,使用方式一模一样。

useState()的操作对象虽然也可以是类的实例,通常来说是分散的普通变量。并且,更新的时候,必须使用useState()的特定更新函数进行更新,直接操作修改变量的话,界面不刷新!

猜猜看,下面的代码,按钮执行后,界面显示的是什么?

import React from "react";
import { useState } from "react";
function App() {
  const [state, setState] = useState({
    name: "苏南大叔",
  });
  const test = () => {
    setState({ name: "新名字" }); // 更新界面,useState()管理的数据正确写法
    state.name = "错误的写法";    // 不更新界面,如果是useReactive()管理的数据,就会正确更新界面
  };
  return (
    <div className="App">
      {state.name}
      <button onClick={test}>修改变量</button>
    </div>
  );
}
export default App;

苏南大叔:React自定义hook,ahooks的useReactive响应式变量管理 - 界面更新的方式
React自定义hook,ahooks的useReactive响应式变量管理(图3-3)

相关链接

可以查看useReactive钩子的源码,代码并不长。但是想要真正理解里面的代码,还是比较费劲的。苏南大叔以前的文章里面,有写过其中的一些内容。包括useState()useRef()useCallback()Proxy()Reflect等等。

参考文章:

结语

React的世界里面,各种use也是遍地开花的,就像当年的jquery插件一样。更多react经验文章,请参考:

如果本文对您有帮助,或者节约了您的时间,欢迎打赏瓶饮料,建立下友谊关系。
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。

 【福利】 腾讯云最新爆款活动!1核2G云服务器首年50元!

 【源码】本文代码片段及相关软件,请点此获取更多信息

 【绝密】秘籍文章入口,仅传授于有缘之人   react