灵活的Redux动作创建者

时间:2018-11-25 20:58:52

标签: reactjs redux react-redux

我正在构建一个相当大的应用程序,除其他外,它具有许多不同的形式和输入字段。每个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”等,其中每种操作类型仅意味着更新商店中的某些字符串。

像这样构造我的通用组件,动作和简化器似乎非常方便,因为我必须编写的测试数量将大大减少。但是,由于我还没有看到其他人这样做(并且我经历了很多回购),所以我有点担心我在这里缺少了一些重要的东西吗?

0 个答案:

没有答案