Я создаю довольно большое приложение, которое, помимо прочего, имеет много разных форм и полей ввода.Каждый редуктор плоский, я использую массив идентификаторов и перебираю их для получения различных предметов из моего магазина, например так:
const state = {
ids: [],
...itemsById
}
Сначала я столкнулся с проблемами, связанными с известной (и решенной) проблемой всегокомпоненты рендерится каждый раз, когда поле ввода изменяется, когда я сопоставляю состояние с реквизитом в компоненте контейнера следующим образом:
const mapStateToProps = (state, { id }) => ({
someProperty: state.reducerName[id].someProperty, // This could be an image or a title, some static property
someInputFieldValue: state.reducerName[id].someInputFieldValue // This prop binding causes re-render every time input changes
})
Моим решением было подключить мой «тупой» компонент поля ввода и сделать егоFlexible Я использовал реквизиты, чтобы указать редуктор, который я хотел получить из поля ввода:
// handleInputFieldChange creates an action that I dispatch and map to props in the container
render() {
const {props: { handleInputFieldChange }} = this
return <InputField handleChange={handleInputFieldChange} reducer="reducerName" fieldName="name" />
}
В компоненте InputField:
const InputField = ({ handleChange, someInputFieldValue }) =>
<input onChange={handleChange} value={someInputFieldValue} />
const mapStateToProps = (state, { id, fieldName, reducerName }) => ({
someInputFieldValue: state[reducerName][id][fieldName].someInputFieldValue
})
export default connect(...)(InputField)
Первый вопрос здесь: это часто встречается?Это анти-паттерн?Каковы предостережения этого решения?
Во-вторых, когда я начал писать более общих создателей действий для этих полей ввода, я понял, что все поля ввода могут обрабатываться одним типом действия: "INPUT_FIELD_CHANGE", иЯ мог бы использовать создателя действий, например, так:
const handleInputFieldChange = ({ id, payload, reducer }) => ({
type: "INPUT_FIELD_CHANGE",
id,
payload,
reducer
})
А потом в моем редукторе:
const { payload, reducer, id } = action
case "INPUT_FIELD_CHANGE":
if (reducer === "reducerName") {
return {...state,
state[id]: { ...state[id], ...payload } }
} else {
return state
}
В другом редукторе у меня будет ...
const { payload, reducer, id } = action
case "INPUT_FIELD_CHANGE":
if (reducer === "anotherReducerName") {
return {...state,
state[id]: { ...state[id], ...payload } }
} else {
return state
}
И тогда я понял, что, вероятно, 80% моих действий и случаев редуктора могут быть написаны таким образом, где все, что я делаю, это обновляет некоторое примитивное значение без дальнейших вычислений и т. Д., Например:
const updateEntity = ({ id, payload, reducer }) => ({
type: 'UPDATE_ENTITY',
id,
payload,
reducer
})
Тогдав КАЖДОМ редукторе:
const { id, payload, reducer } = action
case 'UPDATE_ENTITY':
if (reducer === 'this_very_reducer') {
return {...state,
state[id]: { ...state[id], ...payload }
}
} else {
return state
}
Секция сокращенного шаблона редукторных документов делает что-то похожее, когда они абстрагируются к «updateObject» и т. д., но поскольку они используют только один редуктор спростой тип действия "EDIT_TODO", я не могу точно сказать, что это значит для более крупного приложения, где у меня было бы: "EDIT_TODO", "EDIT_PHONE_NUMBER", "EDIT_USER_NAME" и т. д.Каждый тип действия будет означать только обновление некоторой строки в хранилище.
Кажется, очень удобно структурировать мои общие компоненты, действия и редукторы, как это, так как количество тестов, которые я должен написать, будет уменьшено намного.Но так как я не видел, чтобы кто-то еще делал это (и я прошел через много репозиториев), я немного боюсь, что мне здесь не хватает чего-то важного?