30行代码实现React双向绑定hook的示例代码.docx
第
30行代码实现React双向绑定hook的示例代码
目录使用Proxy代理数据使用useRef创建同一份数据引用添加更新handler去除多次Proxy添加缓存完善代码总结Sandbox示例Vue和MobX中的数据可响应给我们留下了深刻的印象,在React函数组件中我们也可以依赖hooks来实现一个简易好用的useReactive。
看一下我们的目标
constCountDemo=()={
constreactive=useReactive({
count:0,
return(
()={
reactive.count++;
{reactive.count}
/div
};
简单来说就是我们不需要再手动触发setState的handler了,修改数据,组件中的数据就会直接更新。
在Vue中我们实现数据可响应概括来讲需要:
1.解析模板收集依赖
2.发布订阅实现更新
而React函数组件凭借函数的特性这个过程将更加简单,因为函数组件每一次render都会重新执行一遍,我们只需要改变数据之后再触发组件渲染就能达到我们的目的。
因此实现这个自定义hook的核心就是:
1.维护同一份数据
2.劫持对数据的操作
3.在劫持操作中触发组件更新(setState)
使用Proxy代理数据
这个代理模式是实现响应式数据的核心。Vue2.0中使用defineProperty来做数据劫持,现在则是被Proxy模式所替代了,一句话概括defineProperty和proxy的区别就是前者劫持的是属性访问器,而后者可以代理整个对象(Vue3.0,MobX)。
Proxy有多达13种拦截器,我们这次用到的有get,set,delete
constobserver=(initialState,cb)={
constproxy=newProxy(initialState,{
get(target,key,receiver){
constval=Reflect.get(target,key,receiver);
returntypeofval===objectval!==nullobserver(val,cb):val;//递归处理object类型
set(target,key,val){
constret=Reflect.set(target,key,val);
cb();
returnret;
deleteProperty(target,key){
constret=Reflect.deleteProperty(target,key);
cb();
returnret;
returnproxy;
};
上面这个observer完成了对数据的基本操作代理。
这里补充一个知识点:为什么Proxy代理的对象经常搭配Reflect而不是操作符访问?
Reflect更加全面,功能更强大:
只要Proxy对象具有的代理方法,Reflect对象全部具有,以静态方法的形式存在。这些方法能够执行默认行为,无论Proxy怎么修改默认行为,总是可以通过Reflect对应的方法获取默认行为。
比如上文第4行这里Reflect.get(target,key,receiver)咋一看似乎可以和target[key]等价,但实际上不是的看下面的例子,正是由于Reflect的静态方法的第三个参数receiver可以用来指定被调用时的this,所以使用Reflect.get(target,key,receiver)才能如我们预期返回正确结果。
leto={
getb(){
returnthis.a;
leto1=Object.create(
newProxy(o,{
get(target,key,receiver){
returnReflect.get(target,key,receiver);
o1.a=42;
o1.b;//42
leto2=Object.create(
newProxy(o,{
get(target,key){
returntarget[key];
o2.a=42;
o2.b;//undefined
修改某些Object方法的返回结果,