殷勤昨夜三更雨,又得浮生一日凉。——《鹧鸪天》苏轼
实践之结果发布于github,地址:react-duce
不知从何时起,状态管理成了一个前端项目的标配,不论有无需要,我们都会引入诸如MobX、Redux库来管理我们应用的状态。但如果我们回头想想之前项目中的某些架构,不免感叹,为何我的项目功能间设计耦合如此之紧,为什么这部分根本不需要抽离的公共状态却抽离了,又为何组件的状态和UI耦合?
自react发布之初就使用react的同学想必能感叹react发展历程中的每一步都走得稳健,从mixin到class component到function component;从pureComponent到memo,无不是在追求更好的性能与更优的程序范式。实不相瞒,自react 16.8发布hooks,我便爱react更多几分,于此对组件之间状态的管理有了更进一步的思考,完毕,凝结出了这个库react-duce,希望与大家共同探讨hooks在项目中的实践。
为何开发这个库
前段时间,看到一个通信库,swr,基于hook的数据请求库,其设计原理很容易理解,当得到返回的请求数据时,调用状态处理函数,更新状态,进而在使用该状态的组件中得到数据更新。源码片段如下:
import useSWR from 'swr'
function Profile () {
const { data, error } = useSWR('/api/user', fetcher)
if (error) return
if (!data) return
return
}
hook不仅使代码可读性更高,而且可使模块间耦合降低。
部分代码片段实例如下:
import React from 'react';
import { createStore, useStore } from 'react-duce';
// 创建公共store
createStore('countStore', 0);
const HelloContent = () => {
// 使用公共store
const [ count, setCount ] = useStore('countStore');
return (
setCount(count + 1)}>{count}
)
}
const WorldContent = () => {
// 使用公共store
const [ count ] = useStore('countStore');
return (
{count}
)
}
在HelloContent组件中点击span,即可触发count更新,进而WorldContent中的count也得到更新,实现组件之间store共享。
将状态管理交由reducer
曾几何时,我们感叹flux,感叹redux使我们对于状态的管理更加清晰,使我们对数据的流向胸有成竹。
使用实例如下:
import React from 'react';
import { createStore, useStore } from 'react-duce';
// 定义reducer
const reducer = (state, action) => {
// you must return a new state value when a reducer is being used.
switch (action.type) {
case 'add':
const id = state.length;
return [
...state,
{ id, text: action.payload }
];
case 'delete':
return state.filter(todo => todo.id !== action.payload)
default:
return state;
}
}
// 创建指定reducer的store
const todoStore = createStore(
'todoStore',
[
{id: 0, text: 'Sing'}
],
reducer
);
function AddTodo() {
// 返回状态及dispatch函数
const [state, dispatch] = useStore('todoStore');
const inputRef = React.useRef(null);
const onSubmit = e => {
e.preventDefault();
const todo = inputRef.current.value;
inputRef.current.value = '';
// 触发状态更新
dispatch({ type: 'add', payload: todo });
};
return (
Create
);
}
function TodoList() {
const [todos, dispatch] = useStore(todoStore);
const deleteTodo = id => dispatch({ type: 'delete', payload: id });
return (
todolist
{todos.map(todo => (
{todo.text}
deleteTodo(todo.id)} type="button">
X
))}
);
}
export { TodoList, AddTodo };
实现原理
Store基类
class Store {
name;
state;
reducer;
dispatchers;
dispatch;
subscribe(callback) {};
dispatch(action, callback) {};
}
创建store
export function createStore(name, state = {}, reducer) {
const store = new Store(name, state, reducer);
$$stores = Object.assign({}, $$stores, {[name]: store})
}
使用store
export function useStore(identifier) {
const store = getStoreItem(identifier);
// 使用useState创建状态与处理函数
const [state, set] = useState(store.state);
useEffect(() => {
// ...
}, [])
return [state, store.dispatch];
}
当状态函数执行时,状态更新并遍历该状态所有set函数。