React Redux减少器的不变性

时间:2019-11-21 10:00:07

标签: reactjs redux react-redux

如果我以以下方式编写我的reducer,则将调用“ render”方法,并且这是预期的行为。没问题:

const initState = {
    entries: ["test1"]
};

export const EntryReducer = (state = initState, action) => {


    switch (action.type) {


        case ADD_ENTRY:

            return Object.assign({}, state, {
                entries: state.entries.concat("test2")
            });


            break;

        case DELETE_ENTRY:

            break;
    }


    return state;
}

但是,如果我以以下方式编写化简器,则尽管状态正在更新,但未调用“ render”方法:

export const EntryReducer = (state = initState, action) => {

    let newState = Object.assign({}, state);

    switch (action.type) {

        case ADD_ENTRY:

            newState.entries.push("test2");

            break;

        case DELETE_ENTRY:

            break;
    }
    return newState;
}

我不明白为什么渲染器没有被调用。据我了解,“ newState”是一个不可变的对象,不包含对“ state”对象的任何引用。

请帮助我理解它。谢谢。

4 个答案:

答案 0 :(得分:2)

由于Object.assign很浅,因此不会创建新的数组,而旧的数组将被.push()突变:

state.entries === newState.entries // ["test1", "test2"]

答案 1 :(得分:2)

  

“ newState”是一个不变的对象

如果您不自己做,那是普通的对象/数组/等,因此它不是一成不变的。

  

为什么未调用渲染器

React-redux尽力而为,实际上将您的组件包装到PureComponent中。这样做是为了使所有connect()版本的组件不会在调用任何动作时重新呈现,但仅在与相关的商店中更新一次的地方。

要了解相关数据是否已更改,PureComponentoldDataProp !== newDataProp一样进行了比较。突变对象/数组后,检查将失败,因此组件将不会重新呈现。

答案 2 :(得分:1)

您需要使用其他替代方法,因为Object.assign()复制了属性值。如果源值是对对象的引用,则仅复制该引用值。

您应该使用Deep clone。

let newState= JSON.parse(JSON.stringify(state));

答案 3 :(得分:1)

与更新状态的方式无关。认为它是正确的,尽管我不建议您避免使用常见的最佳做法。
在您的情况下,未调用 render ,因为组件属性未更改...
我相信您可能会有这样的事情:

<Component entries={this.props.entries}/>

mapStateToProps = (state) => ({
  entries: state.entries
})

如果是这样,那么state.entries是控制是否重新渲染组件的道具。如果在ADD_ENTRY操作的状态更改期间它具有相同的值,则不会重新渲染该组件。 所以。回到根源。请记住,在JavaScript state.entries中是一个 POINTER ,它指向内存中的数组。
当您调用entries.push时,内存中的数组将被另一个元素扩展-可以。但是我们在state.entries中拥有的 POINTER值将保持不变。它不会改变。这就是Array.push的工作方式。
结果<Component entries={this.props.entries}/>将不会重新呈现。
通过更改newState.entries.push("test2");

newState.entries = newState.entries.concat("test2");

您实际上在更改entries指针,组件看到属性props.entries已更改,现在整个东西都重新呈现了...