我一直在使用React一周,并且在实施提供商时遇到了障碍。我正在使用connect
,mapStateToProps
和mapDispatchToProps
来简化之前正在运行的应用。我有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>
答案 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会推断出状态没有改变,这正是你的例子中发生的事情。
希望这有帮助!