Redux

import { guid } from '../utils'
import { ADD_TODO, TOGGLE_TODO } from './constants'
 
// Исходное состояние
const initialState = [
    {
        id: guid(),
        completed: false,
        expiresAt: '08.04.20201',
        text: 'Купить авокадо 4 шт.'
    }
]

// Редьюсер
const todoList = (state = initialState, action) => {
  switch (action.type) {
        // Добавление новой задачи в список дел
    case ADD_TODO:
      return [
        ...state,
        {
          id: guid(),
          text: action.text,
                    expiresAt: action.expiresAt,
          completed: false
        }
      ]
        // Изменение статуса задачи в списке дел
    case TOGGLE_TODO:
      return state.map(todo =>
        todo.id === action.id ? { ...todo, completed: !todo.completed } : todo
      )
        // Реакция на прочие типы экшенов
    default:
      return state
  }
} 

Работа со множеством редьюсеров

В больших приложениях требуется разделять код хранилища на части. Мы уже говорили, что один из недостатков Redux — его «многословность». Код хранилища будет очень быстро разрастаться. Поэтому, согласитесь, switch-case из 20 тысяч строк — не лучшее решение. При этом для инициализации хранилища нужен один корневой редьюсер, который собирает все части состояния воедино.

Посмотрим, как всё это организовать. Вы уже знаете, что каждый редьюсер — чистая функция, а состояние — объект. Тогда напишем корневой редьюсер для списка дел и представим, что в приложении есть и другие части состояния:

import { combineReducers } from 'redux';

// Редьюсер списка дел
const todoList = (state, action) => { ... }

// Редьюсер пользователя приложения
const user = (state, action) => { ... }

// Редьюсер коллективной работы над списком дел
const collaboration = (state, action) => { ... }

// Корневой редьюсер
const rootReducer = combineReducers({
    todoList,
    user,
    collaboration
}) 

Самое простое хранилище с одним аргументом можно инициализировать так:

import { createStore } from 'redux';
import { rootReducer } from './reducers'; 

const store = createStore(rootReducer); 

Доступ к состоянию хранилища. Компонент Provider

Этот компонент нужен для доступа из приложения к актуальному состоянию хранилища. «Под капотом» Provider использует React.Context. Но если контекст можно применять на любом уровне иерархии, то компонент Provider рекомендуется использовать только на верхнем уровне приложения. Так в хранилище можно обратиться из любой точки приложения, как бы глубоко в иерархии ни находился компонент. В качестве пропсов компонент Provider получает объект store, созданный с помощью известной вам функции createStore():

import { createStore } from 'redux';
import { Provider } from 'react-redux';

import App from './components/app/app';

// Корневой редьюсер, который обрабатывает экшены
import { rootReducer } from './services/reducers';

// Инициализируем хранилище с помощью корневого редьюсера
const store = createStore(rootReducer);

ReactDOM.render(
    // Оборачиваем приложение компонентом Provider из пакета react-redux
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
); 

connect
useSelector
useDispatch
redux-thunk
Redux Devtools
Forms with Redux
Redux Toolkit
React-dnd + Redux

#react