我正在构建一个相当大的应用程序,除其他外,它具有许多不同的形式和输入字段。每个reducer都是扁平的,我使用一个id数组并循环遍历它们,以从我的商店中获取各种物品,就像这样:
const state = {
ids: [],
...itemsById
}
当我将状态映射到容器组件中的props时,每次输入字段发生更改时,我首先遇到一个已知(已解决)整个组件重新渲染的已知问题:
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
})
我的解决方案是连接我的“哑”输入字段组件,并使其变得灵活,我使用道具指定了我想从中获取输入字段值的减速器:
// 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
})
然后在每个reducer中使用
: const { id, payload, reducer } = action
case 'UPDATE_ENTITY':
if (reducer === 'this_very_reducer') {
return {...state,
state[id]: { ...state[id], ...payload }
}
} else {
return state
}
redux文档的reducing boilerplate section在抽象为“ updateObject”等时会执行类似的操作,但是由于它们仅使用具有简单的“ EDIT_TODO”动作类型的单个reducer,因此我无法真正分辨这对于更大的应用意味着什么:“ EDIT_TODO”,“ EDIT_PHONE_NUMBER”,“ EDIT_USER_NAME”等,其中每种操作类型仅意味着更新商店中的某些字符串。
像这样构造我的通用组件,动作和简化器似乎非常方便,因为我必须编写的测试数量将大大减少。但是,由于我还没有看到其他人这样做(并且我经历了很多回购),所以我有点担心我在这里缺少了一些重要的东西吗?