Как стать автором
Обновить
92.11
SimbirSoft
Лидер в разработке современных ИТ-решений на заказ

React + Redux/Effector: инструменты frontend-разработчика для создания интерфейса

Уровень сложностиСредний
Время на прочтение7 мин
Количество просмотров5.7K

Redux и Effector — это две популярные библиотеки, которые используются для  управления состоянием в веб-приложениях. Но если первая широко известна во frontend-разработке, вторая только набирает обороты. В этой статье мы рассмотрим, как работают оба инструмента, разберем преимущества и недостатки и дадим рекомендации по использованию на проектах.  Материал адресован frontend-разработчикам, которые ранее не сталкивались с Redux или хотят найти ему альтернативу.

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

Хорошее определение стейт-менеджерам, на наш взгляд, дал Павел Черторогов

Переменная + Функция + паттерн Observable

Принцип работы стейт-менеджеров
Принцип работы стейт-менеджеров

Вернемся к предмету нашего обзора. По состоянию на 10 августа 2023 года эти две библиотеки имеют следующие показатели:

Effector

Redux

Количество загрузок в неделю

34 493

6 873 885

Звезды на GitHub

~ 4.3K

~ 59.8K

Популярность

Менее популярен, но набирает обороты

Очень популярен

Сообщество

Относительно небольшое, но активное

Огромное и активное

Лицензия

MIT

MIT

Документация

Есть документация, но не очень подробная

Подробная документация

Сложность документации

Сложнее для новичков

Более простая для понимания

Тестирование

Легко тестируется

Сложнее тестировать

Производительность

Имеет хорошую производительность

Менее производителен

Redux 

Redux — это библиотека для управления состоянием приложения в React, разработанная Дэном Абрамовым и Эндрю Кларком в 2015 году. 

Основная идея Redux заключается в том, чтобы иметь единственный источник правды — хранилище (store), в котором хранятся все данные приложения. Действия (actions) и редьюсеры (reducers) используются для изменения состояния в хранилище.

Схема работы Redux
Схема работы Redux

Одним из главных преимуществ Redux является его предсказуемость. Благодаря строгому следованию однонаправленному потоку данных легко понять, как и когда происходит изменение состояния. Также Redux обеспечивает легкую отладку и тестирование кода.

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

// actions.js
export const INCREMENT = 'INCREMENT';
export const DECREMENT = 'DECREMENT';

export const increment = () => {
  return {
    type: INCREMENT
  };
};

export const decrement = () => {
  return {
    type: DECREMENT
  };
};

// reducers.js
import { INCREMENT, DECREMENT } from './actions';

const initialState = {
  count: 0
};

const counterReducer = (state = initialState, action) => {
  switch (action.type) {
    case INCREMENT:
      return {
        ...state,
        count: state.count + 1
      };
    case DECREMENT:
      return {
        ...state,
        count: state.count - 1
      };
    default:
      return state;
  }
};

export default counterReducer;

// store.js
import { createStore } from 'redux';
import counterReducer from './reducers';

const store = createStore(counterReducer);

export default store;

// App.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './actions';

const App = () => {
  const count = useSelector(state => state.count);
  const dispatch = useDispatch();

  return (
    <div>
     <h1>Count: {count}</h1>
<button onClick={() => dispatch(increment())}>
  Increment
</button>
<button onClick={() => dispatch(decrement())}>
  Decrement
</button>
    </div>
  );
};

export default App;

В этом примере создается простой счетчик с помощью Redux. Файл actions.js содержит определение действий, файл reducers.js содержит определение редьюсера, файл store.js создает хранилище Redux, а файл App.js использует хуки useSelector и useDispatch для получения состояния и диспетчера из хранилища и отображает счетчик на странице.

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

Альтернатива — Redux-Toolkit

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

Возьмем для примера предыдущий код и перепишем его, используя Redux-Toolkit:

// actions.js
import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: {
    count: 0
  },
  reducers: {
    increment: state => {
      state.count += 1;
    },
    decrement: state => {
      state.count -= 1;
    }
  }
});

export const { increment, decrement } = counterSlice.actions;

export default counterSlice.reducer;

// store.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './reducers';

const store = configureStore({
  reducer: {
    counter: counterReducer
  }
});

export default store;

// App.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './actions';

const App = () => {
  const count = useSelector(state => state.counter.count);
  const dispatch = useDispatch();

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => dispatch(increment())}>
        Increment
      </button>
      <button onClick={() => dispatch(decrement())}>
        Decrement
      </button>
    </div>
  );
};

export default App;

В этом примере используется функция createSlice из Redux Toolkit для создания среза (slice), который объединяет определение действий и редьюсера в одном месте. Затем этот срез передается в функцию configureStore для создания хранилища Redux. В компоненте App также используются хуки useSelector и useDispatch для получения состояния и диспетчера из хранилища. 

Effector 

Effector был создан в 2019 году Александром Корниенко и является отличной альтернативой Redux. Основная идеология заключается в использовании эффектов (effects) для управления побочными эффектами и изменениями состояния. 

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

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

  2. Приложения с большим объемом данных. Effector обладает высокой производительностью и эффективно работает с большими объемами данных, что делает его подходящим для разработки приложений, которые работают с большими наборами данных или выполняют сложные вычисления.

  3. Приложения, требующие тестирования. Effector предоставляет удобные инструменты для тестирования приложений, позволяя легко создавать и запускать тесты на различные сценарии и проверять корректность работы приложения.

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

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

А теперь давайте перепишем наш счетчик с использованием библиотеки Effector:

// store.js
import { createStore, createEvent } from 'effector';

const increment = createEvent();
const decrement = createEvent();

const counter = createStore(0)
  .on(increment, state => state + 1)
  .on(decrement, state => state - 1);

export { increment, decrement, counter };

// App.js
import React from 'react';
import { useStore } from 'effector-react';
import { increment, decrement, counter } from './store';

const App = () => {
  const count = useStore(counter);

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
};

export default App;

В этом примере мы используем функции createStore и createEvent из Effector для создания хранилища и событий. События increment и decrement вызываются при нажатии на соответствующие кнопки в компоненте App. Состояние счетчика хранится в хранилище counter, которое передается в хук useStore для получения текущего значения.

Кроме того, Effector обладает более эффективной архитектурой, чем Redux. Вместо использования одного глобального хранилища Effector использует граф зависимостей, который позволяет более точно определить, какие части приложения должны быть перерисованы при изменении состояния. Это позволяет улучшить производительность и уменьшить нагрузку на приложение. Также сообщество Effector предлагает при построении архитектуры использовать feature-sliced design. Это уже новый взгляд на архитектуру, достойный отдельной статьи.

Помимо Redux и Effector существуют и другие альтернативы для управления состоянием. Некоторые из них включают MobX, Apollo Client и Zustand. Каждая из этих библиотек имеет свои преимущества, недостатки и решает определенные задачи. Выбор зависит от конкретных потребностей вашего проекта.

Заключение

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

Можно ли обойтись совсем без менеджеров состояний? — Да! Если ваш проект не очень сложный. Например, для написания простого веб-приложения, такого как блог, лендинг, сайта-визитки с несложной логикой, рекомендуем вообще отказаться от менеджера состояний либо использовать React Context.

Спасибо за внимание!

Авторские материалы для frontend-разработчиков мы также публикуем в наших соцсетях – ВКонтакте и Telegram.

Теги:
Хабы:
Всего голосов 4: ↑3 и ↓1+2
Комментарии12

Публикации

Информация

Сайт
www.simbirsoft.com
Дата регистрации
Дата основания
Численность
1 001–5 000 человек
Местоположение
Россия