Интенсивное чтение «Переосмысление Redux»

внешний интерфейс TypeScript React.js Redux

Интенсивное чтение на этой неделе«Переосмысление Redux».

1. Введение

Переосмысление ReduxrematchавторShawn McKayСухая статья написана.

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

Ценность этой статьи заключается в том, что, помимо концепций Mobx и RXjs и только глубокого переосмысления редукции, она очень полезна для большинства инженерных сценариев, которые все еще используют редукс.

2 Обзор

Что относительно ново, так это то, что автор дает формулу для оценки качества фреймворка или инструмента:

工具质量 = 工具节省的时间/使用工具消耗的时间

Если мы оценим нативный избыточность таким образом, мы обнаружим, что дополнительное время, необходимое для использования избыточности, может превышать сэкономленное время, и с этой точки зрения избыточность снизит эффективность работы.

Но идея управления данными в redux верна, и сложные front-end проекты действительно нуждаются в этой идее.Чтобы использовать redux более эффективно, нам нужно использовать фреймворк на основе redux. Автор объясняет, какие проблемы должен решить фреймворк, основанный на редуксе, с шести точек зрения.

Упрощенная инициализация

Код инициализации Redux включает в себя множество концепций, таких какcompose thunkи так далее, покаreducer,initialState,middlewaresЭти три важные концепции разделены на вызовы в стиле функций, а не на более приемлемый стиль конфигурации:

const store = preloadedState => {
  return createStore(
    rootReducer,
    preloadedState,
    compose(applyMiddleware(thunk, api), DevTools.instrument())
  );
};

Если вы измените метод конфигурации, стоимость понимания будет значительно снижена:

const store = new Redux.Store({
  instialState: {},
  reducers: { count },
  middlewares: [api, devTools]
});

Примечание автора: метод инициализации redux очень функционален, а следующий метод настройки более объектно-ориентирован. Напротив, объектно-ориентированный способ лучше понять, ведь хранилище — это объект.instialStateСуществует также та же проблема, по сравнению с оператором отображения, будетpreloadedStateКак параметр функции, он более абстрактен, и присваивание редукса начальному состоянию также относительно скрыто.createStoreНеудобно назначать равномерно одновременно, потому что редукторы разбросаны.Если вы назначаете значения в редукторах, вам нужно использовать функцию параметра по умолчанию es, которая больше похожа на бизнес-мышление, чем на возможность, предоставляемую редуксом.

Упростить редукторы

Гранулярность редуктора Redux слишком велика, что не только приводит к ручному сопоставлению внутри функций.type, тоже принесtype,payloadд., чтобы понять стоимость:

const countReducer = (state, action) => {
  switch (action.type) {
    case INCREMENT:
      return state + action.payload;
    case DECREMENT:
      return state - action.payload;
    default:
      return state;
  }
};

Было бы понятнее установить редьюсеры в конфиге, например, определить объект:

const countReducer = {
  INCREMENT: (state, action) => state + action.payload,
  DECREMENT: (state, action) => state - action.payload
};

Поддержка асинхронного/ожидания

Поддержка динамических данных в редуксе пока довольно трудоемка, нужно разбираться в функциях высшего порядка и понимать, как используется middleware, иначе не будешь знать, почему правильно писать:

const incrementAsync = count => async dispatch => {
  await delay();
  dispatch(increment(count));
};

Почему бы не стереть стоимость понимания и просто позволитьasyncА типы действий?

const incrementAsync = async count => {
  await delay();
  dispatch(increment(count));
};

Примечание автора: Мы обнаружили, что способ рематча, диспетчеризация импортируется (глобальные переменные), а диспетчер редукса вводится.На первый взгляд кажется, что редукс более разумен, но на самом деле я предпочитаю решение рематча. После многолетней практики лучше не использовать потоки данных для компонентов.Достаточно только одного экземпляра потока данных проекта.Дизайн глобальной диспетчеризации на самом деле более разумен, в то время как дизайн инъекционной диспетчеризации, кажется, следует идеально подходит для технологий, но игнорирует сценарии использования в бизнесе, что приводит к излишним и ненужным проблемам.

Изменить действие + редуктор на два действия

Обвинение между абстрактным действием редукса и редуктором очень четкое: действие отвечает за изменение всего, кроме хранилища, а редуктор отвечает за изменение хранилища и иногда используется для обработки данных. Эта концепция на самом деле довольно расплывчата, потому что часто неясно, где обработка данных находится в действии или редюсере, а слишком простой редюсер должен написать действие, соответствующее ему, что кажется слишком формальным и громоздким.

Если переосмыслить проблему, у нас есть только два типа действий:reducer actionа такжеeffect action.

  • действие редуктора: сменить магазин.
  • Действие эффекта: обрабатывает асинхронные сценарии, может вызывать другие действия и не может изменять хранилище.

Синхронные сценарии могут обрабатываться функцией редуктора, требуются только асинхронные сценарии.effect actionС асинхронной частью разобрались, а синхронная часть все еще передана функции редуктора, и обязанности этих двух действий более понятны.

Больше не показывать тип действия объявления

Прекратите хранить типы действий в файле,const ACTION_ONE = 'ACTION_ONE'На самом деле, я неоднократно писал строку, напрямую используя ключ объекта для представления значения действия и добавляя имя хранилища в качестве префикса для обеспечения уникальности.

В то же время Redux рекомендует использоватьpayloadключ для передачи значения, так почему бы не заставить его использоватьpayloadкак ввод, но черезaction.payloadКак насчет стоимости? Использовать напрямуюpayloadЭто не только визуально уменьшает объем кода, его легко понять, но также налагает ограничения на стиль кода, позволяя реализовывать предложения.

Редуктор прямо как ActionCreator

Redux вызывает действие более громоздко, используйтеdispatchили пропустить редуктор черезActionCreatorобертка функций. Почему бы просто не обернуть редуктор автоматическиActionCreatorШерстяная ткань? Сократите шаблонный код и сделайте каждую строку кода значимой.

Наконец, автор даетrematchПолный пример:

import { init, dispatch } from "@rematch/core";
import delay from "./makeMeWait";

const count = {
  state: 0,
  reducers: {
    increment: (state, payload) => state + payload,
    decrement: (state, payload) => state - payload
  },
  effects: {
    async incrementAsync(payload) {
      await delay();
      this.increment(payload);
    }
  }
};

const store = init({
  models: { count }
});

dispatch.count.incrementAsync(1);

3 Интенсивное чтение

Я думаю, что эта статья в основном тщательно анализирует инженерные проблемы редукции, а также дает очень хорошую реализацию.

Максимальная оптимизация деталей

Первый заключается в непосредственном использованииpayloadвместо целогоactionВ качестве входного параметра усиливаются ограничения и упрощается сложность кода:

increment: (state, payload) => state + payload;

Второе использованиеasyncВ функции эффектов используйтеthis.incrementВызов функции, заменаput({type: "increment"})(dva), который имеет поддержку типов в машинописном тексте, может не только использовать автоматические переходы для замены поиска строк, но и проверять типы параметров, что очень редко встречается в среде редукции.

Наконец вdispatchФункция также предоставляет два метода вызова:

dispatch({ type: "count/increment", payload: 1 });
dispatch.count.increment(1);

Если для лучшей поддержки типа или маскиpayloadконцепции, вы можете использовать второе решение, чтобы снова упростить концепцию редукции.

Встроено больше плагинов

rematch интегрирует часто используемые повторный выбор, сохранение, погружение и т. д. в плагины, что относительно усиливает концепцию экологии плагинов. В потоке данных есть дополнительные возможности для кэширования данных, оптимизации производительности и оптимизации процесса разработки.Использование экологии подключаемых модулей является хорошим направлением развития.

Напримерrematch-immerПлагины, вы можете изменить магазин изменяемым образом:

const count = {
  state: 0,
  reducers: {
    add(state) {
      state += 1;
      return state;
    }
  }
};

Но immer не будет работать, когда состояние не является объектом, поэтому лучше разработатьreturn stateпривычка.

Наконец, поговорим о недостатках.reducersОбъявление несовместимо с параметром вызова.

Объявление редукторов несовместимо с параметрами вызова

Например, следующие редукторы:

const count = {
  state: 0,
  reducers: {
    increment: (state, payload) => state + payload,
    decrement: (state, payload) => state - payload
  },
  effects: {
    async incrementAsync(payload) {
      await delay();
      this.increment(payload);
    }
  }
};

когда определеноincrementдва параметра, иincrementAsyncПри его вызове есть только один параметр, что может ввести в заблуждение.stateпомещатьthisсередина:

const count = {
  state: 0,
  reducers: {
    increment: payload => this.state + payload,
    decrement: payload => this.state - payload
  },
  effects: {
    async incrementAsync(payload) {
      await delay();
      this.increment(payload);
    }
  }
};

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

4 Резюме

Повторю авторскую формулу качества инструмента:

工具质量 = 工具节省的时间/使用工具消耗的时间

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

Наконец, я хотел бы поблагодарить автора rematch за дух совершенства, который привносит дальнейшую экстремальную оптимизацию в редукс.

еще 5 обсуждений

Адрес обсуждения:Интенсивное чтение «Переосмысление Redux» · Выпуск №83 · dt-fe/weekly

Если вы хотите принять участие в обсуждении, пожалуйста,кликните сюда, с новыми темами каждую неделю, выходящими по выходным или понедельникам.