Исходное состояние Redux видоизменяется даже при использовании Object.assign - PullRequest
0 голосов
/ 20 ноября 2018

Это простая репликация проблемы, с которой я сталкиваюсь в реальном приложении.https://jsfiddle.net/zqb7mf61/

Обычно, если вы нажмете кнопку «Обновить Todo», текст изменится с «Чистая комната» на «Получить молоко». «Чистая комната» - это значение в исходном состоянии редуктораЗатем в моем React Component я на самом деле пытаюсь клонировать состояние и мутировать клон, чтобы изменить значение на «Get Milk» (Строка 35/36). Удивительно, но само исходное состояние также мутировало, хотя я стараюсь не мутироватьэто (как видно в строке 13).

Мне интересно, почему Object.assign не работает для приставки.

Вот коды из 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);

1 Ответ

0 голосов
/ 20 ноября 2018

Вы используете Object.assign как в редукторе, так и в компоненте.Эта функция копирует только первый уровень переменных внутри объекта.Вы получите новый главный объект, но ссылки на объекты на 2-й глубине остаются прежними.

Например, вы просто копируете ссылку на объект task вместо того, чтобы фактически создавать новый task object.

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...