殷勤昨夜三更雨,又得浮生一日涼。——《鷓鴣天》蘇軾javascript
實踐之結果發佈於github,地址:react-duce前端
不知從什麼時候起,狀態管理成了一個前端項目的標配,不論有無須要,咱們都會引入諸如MobX、Redux庫來管理咱們應用的狀態。但若是咱們回頭想一想以前項目中的某些架構,難免感嘆,爲什麼個人項目功能間設計耦合如此之緊,爲何這部分根本不須要抽離的公共狀態卻抽離了,又爲什麼組件的狀態和UI耦合?java
自react發佈之初就使用react的同窗想必能感嘆react發展歷程中的每一步都走得穩健,從mixin到class component到function component;從pureComponent到memo,無不是在追求更好的性能與更優的程序範式。實不相瞞,自react 16.8發佈hooks,我便愛react更多幾分,於此對組件之間狀態的管理有了更進一步的思考,完畢,凝結出了這個庫react-duce
,但願與你們共同探討hooks在項目中的實踐。react
前段時間,看到一個通訊庫,swr,基於hook的數據請求庫,其設計原理很容易理解,當獲得返回的請求數據時,調用狀態處理函數,更新狀態,進而在使用該狀態的組件中獲得數據更新。源碼片斷以下:git
import useSWR from 'swr'
function Profile () {
const { data, error } = useSWR('/api/user', fetcher)
if (error) return <div>failed to load</div>
if (!data) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
複製代碼
hook不只使代碼可讀性更高,並且可以使模塊間耦合下降。github
部分代碼片斷實例以下:redux
import React from 'react';
import { createStore, useStore } from 'react-duce';
// 建立公共store
createStore('countStore', 0);
const HelloContent = () => {
// 使用公共store
const [ count, setCount ] = useStore('countStore');
return (
<span onClick={() => setCount(count + 1)}>{count}</span>
)
}
const WorldContent = () => {
// 使用公共store
const [ count ] = useStore('countStore');
return (
<span>{count}</span>
)
}複製代碼
在HelloContent組件中點擊span,便可觸發count更新,進而WorldContent中的count也獲得更新,實現組件之間store共享。
api
曾幾什麼時候,咱們感嘆flux,感嘆redux使咱們對於狀態的管理更加清晰,使咱們對數據的流向成竹在胸。架構
使用實例以下:
app
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 (
<form onSubmit={onSubmit}> <input ref={inputRef} /> <button>Create</button> </form> ); } function TodoList() { const [todos, dispatch] = useStore(todoStore); const deleteTodo = id => dispatch({ type: 'delete', payload: id }); return ( <ul> <h2>todolist</h2> {todos.map(todo => ( <li key={todo.id}> {todo.text} <button onClick={() => deleteTodo(todo.id)} type="button"> X </button> </li> ))} </ul> ); } 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函數。