React Hooks 在全局狀態管理中的實踐

1_ivjksIhvAs7TUXbQCxAU0A.png

殷勤昨夜三更雨,又得浮生一日涼。——《鷓鴣天》蘇軾

實踐之結果發佈於github,地址:react-duce前端

不知從什麼時候起,狀態管理成了一個前端項目的標配,不論有無須要,咱們都會引入諸如MobX、Redux庫來管理咱們應用的狀態。但若是咱們回頭想一想以前項目中的某些架構,難免感嘆,爲什麼個人項目功能間設計耦合如此之緊,爲何這部分根本不須要抽離的公共狀態卻抽離了,又爲什麼組件的狀態和UI耦合?react

自react發佈之初就使用react的同窗想必能感嘆react發展歷程中的每一步都走得穩健,從mixin到class component到function component;從pureComponent到memo,無不是在追求更好的性能與更優的程序範式。實不相瞞,自react 16.8發佈hooks,我便愛react更多幾分,於此對組件之間狀態的管理有了更進一步的思考,完畢,凝結出了這個庫react-duce,但願與你們共同探討hooks在項目中的實踐。git

爲什麼開發這個庫

前段時間,看到一個通訊庫,swr,基於hook的數據請求庫,其設計原理很容易理解,當獲得返回的請求數據時,調用狀態處理函數,更新狀態,進而在使用該狀態的組件中獲得數據更新。源碼片斷以下:github

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不只使代碼可讀性更高,並且可以使模塊間耦合下降。typescript

部分代碼片斷實例以下: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

將狀態管理交由reducer

曾幾什麼時候,咱們感嘆flux,感嘆redux使咱們對於狀態的管理更加清晰,使咱們對數據的流向成竹在胸。架構

image-20191115213548135.png

使用實例以下:ide

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函數。

相關文章
相關標籤/搜索