Состояние React / Redux prev постоянно меняется вместе со следующим штатом - PullRequest
0 голосов
/ 01 января 2019

Когда кто-то комментирует, я хочу изменить состояние изображения, чтобы новый комментарий добавлялся на экран.Состояние действительно изменяется, но оно не требует нового рендеринга, потому что старое состояние изменяется вместе с новым состоянием.Я попытался использовать отладчик, и кажется, что строка 40 - то, где старое состояние изменяется.Я очень запутался, потому что я использую Object.freeze (), и я также использую только созданную мной переменную newState и даже не касаюсь старого состояния.Спасибо!

import {
  RECEIVE_ALL_IMAGES,
  RECEIVE_ONE_IMAGE,
  REMOVE_IMAGE,
  REMOVE_IMAGES
} from '../actions/image_actions';

import {
  RECEIVE_LIKE,
  REMOVE_LIKE
} from '../actions/like_actions';

import {
  RECEIVE_COMMENT,
  REMOVE_COMMENT
} from '../actions/comment_actions';

const imagesReducer = (oldState = {}, action) => {
  Object.freeze(oldState);
  let newState = Object.assign({}, oldState);

  switch(action.type){
    case RECEIVE_LIKE:
      newState[action.like.imageId].likerIds.push(action.like.userId);
      return newState;
    case REMOVE_LIKE:
      newState[action.like.imageId].likerIds = newState[action.like.imageId].likerIds.filter(id => id !== action.like.userId);
      return newState;
    case RECEIVE_ALL_IMAGES:
      return Object.assign({}, oldState, action.images);
    case RECEIVE_ONE_IMAGE:
      return Object.assign({}, oldState, {[action.image.id]: action.image});
    case REMOVE_IMAGE:
      delete newState[action.image.id];
      return newState;
    case REMOVE_IMAGES:
      return {};
    case RECEIVE_COMMENT:
      if (newState[action.comment.imageId].comments) {
        newState[action.comment.imageId].comments[action.comment.id] = action.comment;
      } else if (newState[action.comment.imageId]) {
        newState[action.comment.imageId].comments = {};
        newState[action.comment.imageId].comments[action.comment.id] = action.comment;
      }
      return newState
    case REMOVE_COMMENT:
      delete newState[action.comment.imageId].comments[action.comment.id]
      return newState
    default:
      return oldState;
  }
};

export default imagesReducer;

1 Ответ

0 голосов
/ 01 января 2019

Вы только замораживаете и копируете первый слой свойств, но затем вы меняете слои на несколько уровней глубже, и эти свойства все еще используются совместно.Ниже приведен фрагмент, который показывает, что происходит, и один из способов его изменения, но вы можете захотеть взглянуть на использование библиотеки, которая упрощает эту задачу:

const oldState = { 
  id1: { comments: { cid1: 'Comment1' } }, 
  id2: { comments: { cid2: 'Comment2' } }
};

document.getElementById("step1").innerHTML = 'oldState = ' + JSON.stringify(oldState);

Object.freeze(oldState);
const newState = Object.assign({}, oldState);
newState.id1.comments.cid3 = 'Comment3';

document.getElementById("step2").innerHTML = 'oldState = ' + JSON.stringify(oldState) + '<br/>newState = ' + JSON.stringify(newState);

const newStateNoSideEffects = {...oldState};
newStateNoSideEffects.id2 = {...newStateNoSideEffects.id2};
newStateNoSideEffects.id2.comments = {...newStateNoSideEffects.id2.comments, cid4: 'Comment4'};

document.getElementById("step3").innerHTML = 'oldState = ' + JSON.stringify(oldState) + '<br/>newState = ' + JSON.stringify(newState) + '<br/>newStateNoSideEffects = ' + JSON.stringify(newStateNoSideEffects);
<div id="root">
  <div id="step1">
  </div>
  <br/><br/>
  <div id="step2">
  </div>
  <br/><br/>
  <div id="step3">
  </div>
</div>

У вас будет похожая проблема с likerIds.push.

Вот связанный вопрос: Почему я должен использовать immutablejs поверхobject.freeze?

Вот пример использования immutability-helper , который упоминается в React документах :

import React from "react";
import ReactDOM from "react-dom";
import update from "immutability-helper";

function App() {
  const oldState = {
    id1: { comments: { cid1: "Comment1" } },
    id2: { comments: { cid2: "Comment2" } }
  };
  const newState = update(oldState, {
    id1: { comments: { $merge: { cid3: "Comment3" } } }
  });

  return (
    <div className="App">
      <div>oldState = {JSON.stringify(oldState)}</div>
      <div>newState = {JSON.stringify(newState)}</div>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Edit jzm1v32659

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...