反应新手:提供商在减速器执行时不更新

时间:2018-01-22 15:00:02

标签: reactjs redux react-redux

我一直在使用React一周,并且在实施提供商时遇到了障碍。我正在使用connectmapStateToPropsmapDispatchToProps来简化之前正在运行的应用。我有CommentsContainer组件链接到Comments组件,该组件映射了子Comment组件。我在onDeleteClick组件的Comment事件中实施的第一个操作是onClick。我认为这很简单,但是在事件触发后我无法让页面重新呈现更新状态(也就是删除已删除的Comment组件)。 Chrome检查员确认:

  • 减速机案例正在解雇
  • 已删除的评论正在从州
  • 中删除

但是状态根本就没有更新。我以为我已经掌握了状态如何触发,但我想我错过了一些东西。以下相关代码,非常感谢任何想法。

App.js(主要访问点)

import React from 'react';
import CommentsContainer from './components/CommentsContainer';
import { createStore } from 'redux';
import commentsReducer from './reducers/CommentsReducer';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';

const store = createStore(commentsReducer);
const rootEl = document.getElementById('root');

const render = () => ReactDOM.render(
  <Provider store={store}><CommentsContainer /></Provider>, rootEl
)

CommentsContainer.js

import React from 'react';
import { connect } from 'react-redux';
import Comments from './Comments';
import { removeComment } from '../actions/CommentsAction';

const mapStateToProps = state => {
  return {
    comments: state
  }
}

const mapDispatchToProps = dispatch => {
  return  {
    onDeleteClick: id => {
      dispatch(removeComment(id))
    }
  }
}

const CommentsContainer = connect(
  mapStateToProps,
  mapDispatchToProps
)(Comments);

export default CommentsContainer;

Comments.js

import React from 'react';
import Comment from './Comment';

const Comments = ({ comments, onDeleteClick }) => (
  <div className='comments'>{comments.map((comment) => (<Comment key={comment.id} comment={comment} onDeleteClick={onDeleteClick} />))}
  </div>
)

export default Comments;

Comment.js

import React from 'react';

const Comment  = ({ comment, onDeleteClick}) => (
  <div className='comment'>
    <div className='comment-user'>{comment.user}</div>
    <div className='comment-content'>{comment.content}</div>
    <div className='delete-comment' onClick={(e) => { onDeleteClick(comment)}}>Delete</div>
  </div>
)

export default Comment;

CommentsReducer.js

import * as constants from '../Constants';

const CommentsReducer = (state=[
  {id: '123', user: 'Test Reducer User', content: 'Test Content'},
  {id: '456', user:  'Other Reducer User', content: 'Other Content'}
], action) => {

  let comments;

  switch(action.type) {
    case constants.REMOVE_COMMENT:
      comments = state;
      for (let i = comments.length - 1; i >= 0; i--) {
        if (comments[i].id == action.comment.id) {
          comments.splice(i,1);
          break;
        }
      }
      break;
    default:
      comments = state;
  }

  return comments;
}

export default CommentsReducer;

CommentsAction.src

import * as constants from '../Constants';

export const removeComment = comment => {
  return {
    type: constants.REMOVE_COMMENT,
    comment
  }
}

Constants.js

export const REMOVE_COMMENT = 'REMOVE_COMMENT';

的index.html

<!DOCTYPE html>
<html>
  <head>
    <title>Demo React App</title>
  </head>
  <body>
    <div id="root"></div>
    <div id='commentForm'></div>
  </body>
</html>

3 个答案:

答案 0 :(得分:1)

避免在React中直接改变数组/对象的状态。

而不是comments.splice(index, 1),请在reducer中使用return comments.filter(comment => comment.id !== removeId)

React-Redux应用程序中的不可变性非常重要,许多内部性能改进技巧(例如,shouldComponentUpdate)依赖于它。

答案 1 :(得分:1)

使用Redux时,请确保从不改变状态。始终返回新状态(如果状态发生变化)。在那种观点中,你的减速器基本上是在改变状态。使用.slice().filter()或对象扩展运算符等函数创建新状态。有关详细信息,请参阅https://redux.js.org/docs/recipes/reducers/ImmutableUpdatePatterns.html

你的减速机应该是:

const CommentsReducer = (state=[
  {id: '123', user: 'Test Reducer User', content: 'Test Content'},
  {id: '456', user:  'Other Reducer User', content: 'Other Content'}
], action) => {

  let comments;

  switch(action.type) {
    case constants.REMOVE_COMMENT:
      comments = [...state];        // use of object spread operator. You can also do comments = state.slice() or use filter() function
      for (let i = comments.length - 1; i >= 0; i--) {
        if (comments[i].id == action.comment.id) {
          comments.splice(i,1);
          break;
        }
      }
      break;
    default:
      comments = state;
  }

  return comments;
}

答案 2 :(得分:1)

Redux(您决定使用的州商店)背后的核心原则之一 是不可移植的。

这意味着你获得了CommentsReducer中的当前状态,并且应该返回一个新状态(如在一个全新的javascript对象中)

你的reducer 改变当前状态,而不是返回一个包含评论减少的评论的全新对象。

这样的事情会有所帮助: 请注意我假设您的状态是一个对象而不是您使用的数组。 这样,每次想要改变状态时,使用Object.assign()就可以轻松地从头开始创建一个全新的对象。

  case constants.REMOVE_COMMENT:
    return Object.assign({}, state, {
      comments: state.comments.filter(c => c.id !== action.comment.id)
    });

请注意,这是Redux注意到您的应用程序状态发生变化的能力背后的全部内容(它比较了先前状态的对象指针和减速器返回的新状态)

如果对象是同一个实例,Redux会推断出状态没有改变,这正是你的例子中发生的事情。

希望这有帮助!