Мой вопрос о том, как структурировать редукторы и создателей действий, чтобы правильно их использовать.
Я прочитал тонны библиографии в Интернете о составе редукторов и редукторах более высокого порядка и сумел сделать некоторые шаги в правильном направлении, создав фабрику / генератор редукторов с пространством имен. Благодаря этому у меня могут быть разные экземпляры одного и того же компонента / представления с независимыми состояниями, которые имеют общее поведение. Однако это не относится к компонентам / представлениям, которые имеют общие основания, но не равны. Скажем ... показать и отредактировать представление для объекта.
При монтировании оба эти компонента должны извлекать данные сущности из API одинаковым образом, однако компонент show обладает гораздо меньшими возможностями, чем компонент редактирования, который также обрабатывает отправку формы, обрабатывает ошибки и т. Д ...
Итак, сказав, что ... как я предполагаю расширить создателей действий editEntityReducer и editEntity, чтобы включить в них создателей действия entityReducer и entity, а также редактировать собственные функции редуктора и создателей действий?
Это то, что я имею до сих пор, используя в качестве примера сущность User:
Пользовательский редуктор + создатели действий (user.js):
import normalize from 'jsonapi-normalizer'
import { api, authenticatedHeaders } from 'api'
import { RSAA } from 'redux-api-middleware'
import { List, Record } from 'immutable'
import * as constants from './constants'
// ------------------------------------
// Actions
// ------------------------------------
export const destroyUser = (userId) => {
// Uses redux-api-middleware. see: https://github.com/agraboso/redux-api-middleware
return {
[RSAA]: {
endpoint: api.users.destroy.path(userId),
method: api.users.destroy.method,
headers: (state) => authenticatedHeaders(state.session.authorization.token),
types: [
constants.DESTROY_START,
constants.DESTROY_SUCCESS,
constants.DESTROY_FAIL]
}
}
}
export const fetchUser = (userId) => {
// Uses redux-api-middleware. see: https://github.com/agraboso/redux-api-middleware
return {
[RSAA]: {
endpoint: api.users.show.path(userId),
method: api.users.show.method,
headers: (state) => authenticatedHeaders(state.session.authorization.token),
types: [
constants.FETCH_START,
{
type: constants.FETCH_SUCCESS,
payload: (action, state, res) => {
return res.json().then(json => normalize(json))
}
},
constants.FETCH_FAIL]
}
}
}
// ------------------------------------
// Action Handlers
// ------------------------------------
const ACTION_HANDLERS = (prefix) => {
return {
[`${prefix}_${constants.DESTROY_START}`]: (state, action) => {
return state.set('destroying', true)
},
[`${prefix}_${constants.DESTROY_SUCCESS}`]: (state, action) => {
return state.set('destroying', false)
},
[`${prefix}_${constants.DESTROY_FAIL}`]: (state, action) => {
return state.set('destroying', false)
},
[`${prefix}_${constants.FETCH_START}`]: (state, action) => {
return state.set('loading', true)
},
[`${prefix}_${constants.FETCH_SUCCESS}`]: (state, { payload }) => {
const users = payload.entities.user
const userIds = payload.result.user
const roles = payload.entities.role
// It's a single record fetch
const user = users[userIds[0]]
return state.merge({
loading: false,
record: Record({ user: Record(user)(), roles: Record(roles)() })()
})
},
[`${prefix}_${constants.FETCH_FAIL}`]: (state, action) => {
return state.set('loading', false)
}
}
}
// ------------------------------------
// Reducer
// ------------------------------------
const initialState = Record({
destroying: false,
loading: true, // initially true so will only go to false upong user loaded
record: Record({ user: Record({})(), roles: List([]) })()
})()
const userReducer = (prefix = 'USER') => {
if (prefix === undefined || prefix.length < 1) {
throw new Error('prefix must be defined')
}
return (state = initialState, action) => {
const handler = ACTION_HANDLERS(prefix)[`${prefix}_${action.type}`]
return handler ? handler(state, action) : state
}
}
export default userReducer
Редактирование пользовательского редуктора и создателей действий (edit_user.js):
import normalize from 'jsonapi-normalizer'
import { api, authenticatedHeaders } from 'api'
import { RSAA } from 'redux-api-middleware'
import { List, Record } from 'immutable'
import * as constants from './constants'
// ------------------------------------
// Actions
// ------------------------------------
export const updateUser = (userId, params = {}) => {
// Uses redux-api-middleware. see: https://github.com/agraboso/redux-api-middleware
return {
[RSAA]: {
endpoint: api.users.update.path(userId),
method: api.users.update.method,
headers: (state) => authenticatedHeaders(state.session.authorization.token),
types: [
constants.USER_UPDATE_START,
constants.USER_UPDATE_SUCCESS,
constants.USER_UPDATE_FAIL]
}
}
}
// TODO: see how to reuse this from the user.js file!
export const fetchUser = (userId) => {
// Uses redux-api-middleware. see: https://github.com/agraboso/redux-api-middleware
return {
[RSAA]: {
endpoint: api.users.show.path(userId),
method: api.users.show.method,
headers: (state) => authenticatedHeaders(state.session.authorization.token),
types: [
constants.USER_FETCH_START,
{
type: constants.USER_FETCH_SUCCESS,
payload: (action, state, res) => {
return res.json().then(json => normalize(json))
}
},
constants.USER_FETCH_FAIL]
}
}
}
// ------------------------------------
// Action Handlers
// ------------------------------------
const ACTION_HANDLERS = {
[constants.USER_UPDATE_START]: (state, action) => {
return state.set('loading', true)
},
[constants.USER_UPDATE_SUCCESS]: (state, action) => {
return state.set('loading', false)
},
[constants.USER_UPDATE_FAIL]: (state, action) => {
return state.set('loading', false)
},
// TODO: this reducers are the same as user.js, reuse them!!
[constants.USER_FETCH_START]: (state, action) => {
return state.set('loading', true)
},
[constants.USER_FETCH_SUCCESS]: (state, { payload }) => {
const users = payload.entities.user
const userIds = payload.result.user
const roles = payload.entities.role
// It's a single record fetch
const user = users[userIds[0]]
return state.merge({
loading: false,
record: Record({ user: Record(user)(), roles: Record(roles)() })()
})
},
[constants.USER_FETCH_FAIL]: (state, action) => {
return state.set('loading', false)
}
}
// ------------------------------------
// Reducer
// ------------------------------------
const initialState = Record({
loading: true, // initially true so will only go to false upong user loaded
record: Record({ user: Record({})(), roles: List([]) })()
})()
export default function editUserReducer (state = initialState, action) {
const handler = ACTION_HANDLERS[action.type]
return handler ? handler(state, action) : state
}
Как вы можете видеть в коде TODO в коде, я хочу иметь возможность повторно использовать эти части редуктора и создателя действия, поскольку он может быть использован не только для базовых операций сущности, но и для любой общей операции CRUD на любом ресурсе, который мой приложение может использовать!
Спасибо