Подготовка данных для объекта action в Redux

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

Давайте откроем наше приложение с продуктами, а в нем файл NewProductForm.jsx. Обратите внимание на следующую строчку кода:

NewProductForm.jsxdispatch(productAdded({
  id: nanoid(), name, desc, price, amount
}))

Здесь мы собираем payload объект прямо в React компоненте и передаем его в экшен productAdded. А что если нам придется отправлять такой же экшен из нескольких компонентов или логика для сборки окажется сложной? По идее нашему компоненту должно быть все равно как выглядит объект в payload для данного action. К тому же нас не устраивает постоянное дублирование кода.

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

jsx{reducer, prepare}

Давайте откроем наш файл productsSlice.js и изменим код для редьюсера productAdded. Теперь этот кусочек кода:

products/ProductSlice.jsproductAdded(state, action) {
  state.push(action.payload)
},

Мы поменяем на следующий, в котором функция reducer будет заниматься обновлением стейта в store, а prepare - возвращать объект payload со сгенерированным id и другими нашими данными:

products/ProductSlice.jsproductAdded: {
  reducer(state, action) {
    state.push(action.payload)
  },
  prepare(name, desc, price, amount) {
    return {
      payload: {
        id: nanoid(),
        name,
        desc,
        price,
        amount,
      },
    }
  },
},

Так как теперь мы будем генерировать id здесь, а не в компоненте, давайте добавим nanoid в импорт:

products/ProductSlice.jsimport { createSlice, nanoid } from '@reduxjs/toolkit'

Напоследок внесем изменения в NewProductForm.jsx. Вместо строчки:

products/NewProductForm.jsxdispatch(productAdded({
  id: nanoid(), name, desc, price, amount
}))

У нас будет такая, в которой мы просто через запятую передадим необходимые нам данные (не забудьте в этом файле убрать nanoid из импорта):

products/NewProductForm.jsxdispatch(productAdded(name, desc, price, amount))

Запустим приложение, затем создадим новый продукт и убедимся, что мы ничего не поломали.

Задание 1

Откройте ваше приложение со студентами. В файле StudentsSlice.js перепишите ваш редьюсер studentAdded таким образом, чтобы он был в виде объекта {reducer, prepare}, как показано в уроке.

Задание 2

Внесите соответствующие изменения в файл NewStudentForm.jsx, как показано в уроке. Запустите приложение и убедитесь, что все работает как и прежде.