- Published on
useReactive
- Authors

- Name
- 李丹秋
提供一种数据响应式的操作体验,定义数据状态不需要写 useState,直接修改属性即可刷新视图。
### 示例
``` TSX
import React from 'react';
import { useReactive } from 'front-base-hooks';
export default () => {
const state = useReactive({
count: 0,
inputVal: '',
obj: {
value: '',
},
});
return (
<div>
<p> state.count:{state.count}</p>
<button style={{ marginRight: 8 }} onClick={() => state.count++}>
state.count++
</button>
<button onClick={() => state.count--}>state.count--</button>
<p style={{ marginTop: 20 }}> state.inputVal: {state.inputVal}</p>
<input onChange={(e) => (state.inputVal = e.target.value)} />
<p style={{ marginTop: 20 }}> state.obj.value: {state.obj.value}</p>
<input onChange={(e) => (state.obj.value = e.target.value)} />
</div>
);
};
源码
import isPlainObject from 'lodash/isPlainObject';
import { useMemo, useRef } from 'react';
import useUpdate from '../useUpdate';
const proxyMap = new WeakMap();
const rawMap = new WeakMap();
function observer<T extends Record<string, any>>(initialValue: T, cb: () => void): T {
const existingProxy = proxyMap.get(initialValue);
if (existingProxy) {
return existingProxy;
}
// 防止代理已经代理过的对象
// https://github.com/alibaba/hooks/issues/839
if (rawMap.has(initialValue)) {
return initialValue;
}
const proxy = new Proxy<T>(initialValue, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver);
// Only proxy plain object or array,
// otherwise it will cause: https://github.com/alibaba/hooks/issues/2080
// 如果是对象或者数组,就递归代理
return isPlainObject(res) || Array.isArray(res) ? observer(res, cb) : res;
},
set(target, key, val) {
const ret = Reflect.set(target, key, val);
// 更新ref的值,并且触发重新渲染
cb();
return ret;
},
deleteProperty(target, key) {
const ret = Reflect.deleteProperty(target, key);
cb();
return ret;
},
});
proxyMap.set(initialValue, proxy);
rawMap.set(proxy, initialValue);
return proxy;
}
function useReactive<S extends Record<string, any>>(initialState: S): S {
const update = useUpdate();
const stateRef = useRef<S>(initialState);
// 使用一个ref去存储值,后续set也是执行ref的修改
const state = useMemo(() => {
return observer(stateRef.current, () => {
update();
});
}, []);
return state;
}
export default useReactive;
整个代码理解起来还是比较容易,就是方式了使用setState这种方式,而是通过代理的方式去监听initState(用ref存储)的变化,然后出发update(useUpdate前面代码有分析过)逻辑,有点类似于vue3的方式,通过代理完成响应式