Практика React Hooks в глобальном управлении состоянием

React.js


Прошлой ночью Инь Цинь шел дождь в третью ночь, и снова был холодный день. —— «Небеса куропатки» Су Ши

Результаты практики опубликованы на github по адресу:react-duce

Я не знаю, с каких пор управление состоянием стало стандартом фронтенд-проекта.Нужно нам это или нет, мы введем такие библиотеки, как MobX и Redux, для управления состоянием нашего приложения. Но если мы оглянемся назад на некоторые из архитектур в предыдущем проекте, мы не сможем не вздохнуть, почему дизайн связывает функции моего проекта так тесно, почему эта часть публичного состояния, которая не нуждается в извлекаться вообще, но почему извлекается состояние компонентов?В сочетании с пользовательским интерфейсом?

Студенты, которые использовали React с момента выпуска React, должны быть в состоянии вздохнуть, что каждый шаг в процессе разработки React шел стабильно, от миксина до компонента класса и функционального компонента; от чистого компонента до меморандумов — все они стремятся к лучшей производительности и лучшему Парадигма программы производительности. Если честно, с момента выхода хуков в react 16.8 мне больше понравился react, я еще подумал об управлении состоянием между компонентами, после чего сконденсировал эту библиотеку.react-duce, надеюсь обсудить с вами практику хуков в проекте.

почему эта библиотека была разработана

Некоторое время назад я видел коммуникационную библиотеку swr, библиотеку запросов данных, основанную на хуках, принцип ее построения прост для понимания, когда возвращаемые данные запроса получены, вызывается функция обработки состояния для обновления состояния, а затем получается в компоненте, использующем состояние Data Update. Фрагмент исходного кода выглядит следующим образом:

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>
}

Хуки не только делают код более читабельным, но и уменьшают связь между модулями.

Ниже приведены некоторые примеры фрагментов кода:

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>
  )
}

Нажмите span в компоненте HelloContent, чтобы вызвать обновление счетчика, а затем счетчик в WorldContent также обновится, реализуя совместное использование хранилища между компонентами.

Оставьте управление состоянием редюсеру

Когда-то мы сетовали на поток, сетовали на то, что избыточность делает наше управление состоянием более понятным и вселяет в нас уверенность в потоке данных.


Примеры использования следующие:

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 };

Принцип реализации

Магазин базового класса

class Store {
  name;
  state;
  reducer;
  dispatchers;
  dispatch;
  
  subscribe(callback) {};
  
  dispatch(action, callback) {};
}

создать магазин

export function createStore(name, state = {}, reducer) {
  const store = new Store(name, state, reducer);
  ?stores = Object.assign({}, ?stores, {[name]: store})
}

использовать магазин

export function useStore(identifier) {
  const store = getStoreItem(identifier);
  // 使用useState创建状态与处理函数
  const [state, set] = useState(store.state);
  
  useEffect(() => {
    // ...
  }, [])
  
  return [state, store.dispatch];
}

Когда функция состояния выполняется, состояние обновляется и просматриваются все установленные функции состояния.