React自定义hook,ahooks的useReactive响应式变量管理
发布于 作者:苏南大叔 来源:程序如此灵动~本文说一下React
的自定义钩子useReactive()
的实现和应用方法,它来自ahooks
这个著名的react hooks
库。它对标的是react
官方的useState()
。当然,也不能说useReactive()
钩子就一定比useState()
钩子先进,两者各有所长。
苏南大叔的“程序如此灵动”博客,记录苏南大叔的代码编程经验总结。本文测试环境:nodejs@20.18.0
,create-react-app@5.0.1
,react-router-dom@6.27.0
,react@18.3.1
,ahooks@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
,虽然确实变化了。但不会引起界面的更新,不够“响应式”。
被react
的useState
接管的变量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;
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
范畴的操作,请使用redux
的useSelector()
。
更新方式区别
useReactive()
的操作对象,是个类的实例{}
。使用方式上,就是在定义的时候,多了个useReactive({})
字样,其它的地方,和普通的js
非react
相比,使用方式一模一样。
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;
相关链接
可以查看useReactive
钩子的源码,代码并不长。但是想要真正理解里面的代码,还是比较费劲的。苏南大叔以前的文章里面,有写过其中的一些内容。包括useState()
、useRef()
、useCallback()
、Proxy()
和Reflect
等等。
参考文章:
- https://newsn.net/say/react-usestate.html
- https://newsn.net/say/react-useref.html
- https://newsn.net/say/react-usecallback.html
- https://newsn.net/say/js-proxy.html
- https://newsn.net/say/js-proxy-2.html
- https://newsn.net/say/js-reflect.html
结语
React
的世界里面,各种use
也是遍地开花的,就像当年的jquery
插件一样。更多react
经验文章,请参考:
本博客不欢迎:各种镜像采集行为。请尊重原创文章内容,转载请保留作者链接。