#6 ReduxJS - combineReducers

poster
В этом уроке мы познакомимся с методом combineReducers. Научимся разбивать большие редьюсеры на более мелкие.
Понравилось? Поделитесь с друзьями!
Понравилось?
Поделитесь с друзьями!
Комментарии
Текст видео

Всем привет. В этом уроке мы продолжаем изучать redux и сегодня мы поговорим о композиции редьюсеров.

Функция playlist, которую мы с вами писали ранее - это редьюсер.

function playlist(state = initialState, action) {
  if (action.type === 'ADD_TRACK') {
    return [
      ...state,
      action.payload
    ];
  }
  return state;
}

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

Теперь представим, что нам в приложении нужно хранить не только треки, но и плейлисты. Мы можем сделать initialState обьектом с полями tracks, playlists.

const initialState = {
  tracks: [
    'Smells like spirit',
    'Enter Sandman'
  ],
  playlists: [
    'My home playlist',
    'My work playlist'
  ]
};

Тогда у нас изменится и редьюсер.

function playlist(state = initialState, action) {
  if (action.type === 'ADD_TRACK') {
    return {
      ...state,
      tracks: [...state.tracks, action.payload]
    };
  }
  return state;
}

Мы возвращаем теперь не массив, а обьект. У обьекта мы обновляем массив треков добавляя в него новый трек. Работа с данными немного усложнилась, так как мы теперь возвращаем обьект, а не массив и у нас уже не плоские данные.

Теперь нам нужно обновить connect.

export default connect(
  state => ({
    tracks: state.tracks
  }),
  dispatch => ({
    onAddTrack: (trackName) => {
      dispatch({ type: 'ADD_TRACK', payload: trackName });
    }
  })
)(App);

Теперь мы присваиваем в this.props.tracks данные из state.tracks. Также нужно поменять переменную testStore на this.props.tracks

{this.props.tracks.map((track, index) =>
  <li key={index}>{track}</li>
)}

Как мы видим, приложение работает так же, как в прошлом уроке. Давайте проверим как у нас выглядит store. В redux-devtools мы видим track и playlists.

Как бы выглядел наш редьюсер, когда у нас было мы много екшенов?

function playlist(state = initialState, action) {
  if (action.type === 'ADD_TRACK') {
    return {
      ...state,
      tracks: [...state.tracks, action.payload]
    };
  } else if (action.type === 'DELETE_TRACK') {
    return state;
  } else if (action.type === 'ADD_PLAYLIST') {
    return state;
  } else if (action.type === 'DELETE_PLAYLIST') {
    return state;
  }
  return state;
}

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

Даже в таком примере уже видно, что его можно разделить на 2 редьюсера. Один редьюсер будет работать с плейлистами, а один с треками. Для этого в redux существует функция combineReducers.

Давайте создадим папку reducers и файл index.js. Внутри импортируем функцию combineReducers.

import { combineReducers } from 'redux'

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

import tracks from './tracks';

export default combineReducers({
  tracks
})

Создадим файл tracks и перенесем туда наш редьюсер, изменив его на старый код. Обратите внимание, насколько легче сразу читается код. Так как у нас state треков стал опять плоским, а не полем обьекта, то эти с этими данными легче работать. Всегда нужно стараться делать state как можно более плоским.

Тоже самое сделаем с плейлистами

const initialState = [
    'My home playlist',
    'My work playlist'
];

export default function playlists(state = initialState, action) {
  if (action.type === 'ADD_PLAYLIST') {
    return state;
  } else if (action.type === 'DELETE_PLAYLIST') {
    return state;
  }
  return state;
}

и добавим плейлисты в combineReducers.

import { combineReducers } from 'redux';

import tracks from './tracks';
import playlists from './playlists';

export default combineReducers({
  tracks,
  playlists
})

Теперь в index.js импортируем наш редьюсер и передаем его как первый параметр.

import reducer from './reducers';
const store = createStore(reducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__());

Если мы посмотрим в браузер, то наше приложение работает, а в redux-devtools мы по прежнему видим обьект с двумя полями tracks и playlists.

С помощью combineReducers можно разбивать редьюсеры на любом уроке вложенности. Мы могли бы, например, разбить reducer tracks на несколько внутри, когда он станет слишком сложным.

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

Только зарегистрированные пользователи могут оставлять комментарии.  Войдите, пожалуйста.
Hovhannes Badasyan
2 лет назад
очень хороший урок, ну лично для меня это супер
monsterlessons
2 лет назад
Спасибо