【问题标题】:Redux initial state gets mutated even when using Object.assign即使使用 Object.assign,Redux 初始状态也会发生变化
【发布时间】:2018-11-20 10:02:31
【问题描述】:

这是我在实际应用中遇到的问题的简单复制。 https://jsfiddle.net/zqb7mf61/

基本上,如果您单击“更新 Todo”按钮,文本将从“Clean Room”变为“Get Milk”。“Clean Room”是减速器初始状态中的值。然后在我的 React 组件中,我实际上尝试克隆状态并改变克隆以将值更改为“获取牛奶”(第 35/36 行)。令人惊讶的是,即使我尝试不改变初始状态本身也发生了突变(如在线所示13 个)。

我想知道为什么 Object.assign 不适用于 redux。

这是来自 jsFiddle 的代码。

REDUX

const initState = {
    task: {id: 1, text: 'Clean Room'}
}

// REDUCER
function todoReducer (state = initState, action) {
  switch (action.type) {
   case 'UPDATE_TODO':
        console.log(state)
        let newTodo = Object.assign({}, state)  // here i'm trying to not make any changes. But i am surpise that state is already mutated.
      return newTodo
    default:
        return state;
  }
}

// ACTION CREATORS:
function updateTodo () {
    return {type: 'UPDATE_TODO'};
}


// Create Store
var todoStore = Redux.createStore(todoReducer);

反应组件

//REACT COMPONENT
 class App extends React.Component{
    _onSubmit = (e)=> {
    e.preventDefault();
    let newTodos = Object.assign({}, this.props.todos)  // here i clone the redux state so that it will not be mutated, but i am surprise that it is mutated and affected the reducer.
    newTodos.task.text = 'Get Milk'
    console.log(this.props.todos)
    this.props.updateTodo();
  }

    render(){
    return (
        <div>
        <h3>Todo List:</h3>
        <p> {this.props.todos.task.text} </p>

        <form onSubmit={this._onSubmit} ref='form'>
          <input type='submit' value='Update Todo' />
        </form>      

      </div>
     );
  }
 }

// Map state and dispatch to props
function mapStateToProps (state) {
    return {
    todos: state
    };
}

function mapDispatchToProps (dispatch) {
    return Redux.bindActionCreators({
    updateTodo: updateTodo
  }, dispatch);
 }
  // CONNECT TO REDUX STORE
 var AppContainer = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(App);

【问题讨论】:

    标签: javascript reactjs redux


    【解决方案1】:

    您在减速器和组件中都使用Object.assign。此函数仅复制对象内的第一级变量。您将获得一个新的主对象,但对第二个深度对象的引用仍然相同。

    例如您只需复制对 task 对象的引用,而不是实际创建一个新的 task 对象。

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign#Deep_Clone


    除此之外,最好不要将整个状态加载到您的组件中并以不同的方式处理操作。让我们暂时解决这个问题。您必须在 onSubmit 中创建一个新任务对象,而不是为对象引用分配新文本。这看起来像这样:

    newTodos.task = Object.assign({}, newTodos.task, {text: 'Get Milk'})
    

    此外,要实际更新商店,您必须编辑减速器,因为您现在将当前状态分配给新状态。这条新线如下所示:

    let newTodo = Object.assign({}, action.todos)
    

    【讨论】:

    • 出色的答案。我一直认为 Object.assign 做了一个深度克隆。难怪当我使用 JSON.parse(JSON.stringify(todos)) 时,它会像我预期的那样工作,但不是 Object.assign。
    猜你喜欢
    • 2020-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-29
    • 2020-02-22
    • 1970-01-01
    • 2022-10-14
    • 1970-01-01
    相关资源
    最近更新 更多