点击点赞/取消点赞按钮后如何让React立即重新渲染?
问题核心错误点
- action传递的payload参数缺失:你调用Firebase接口返回的响应里没有携带
postId、username等字段,reducer里无法匹配到要更新的帖子 - reducer状态更新逻辑错误:你组件里
LikedBy是对象结构,但代码里用了数组的concat方法,另外forEach没有返回值,会导致state.Data被赋值为undefined,自然会报res.map不是函数的错误 - 取消点赞的reducer完全没有修改状态:直接返回原有的
state.Data,Redux检测到状态引用没有变化,不会触发组件重渲染,所以需要手动刷新才能看到效果 - 组件里的
forceUpdate完全没必要,只要Redux状态正确更新,props变化后组件会自动重渲染
1. 首先修改action函数,把需要的参数完整传递给reducer
export const likePost = (username, postId) => { const req = { username } return (dispatch) => { axios.post(`/Data/${postId}/LikedBy.json`, req) .then((res) => { dispatch({ type: actionTypes.Like_Post, payload: { postId, likeId: res.data.name, // Firebase返回的新增点赞记录的唯一key username } }) }) } } export const unlikePost = (postId, unlikeId) => { return (dispatch) => { axios.delete(`/Data/${postId}/LikedBy/${unlikeId.id}.json`) .then((res) => { dispatch({ type: actionTypes.Unlike_Post, payload: { postId, unlikeId: unlikeId.id } }) }).catch((error) => { console.log(error) }) } }
2. 修改reducer逻辑,按照对象结构更新LikedBy字段,每次返回新的状态引用
const initialState = { Data: [], loading: false } const reducer = (state = initialState, action) => { switch(action.type){ case actionTypes.Like_Post: return { ...state, Data: state.Data.map((post) => { if(post.id === action.payload.postId) { return { ...post, LikedBy: { ...post.LikedBy, // 新增点赞记录 [action.payload.likeId]: { username: action.payload.username } } } } return post }), loading: false, } case actionTypes.Unlike_Post: return { ...state, Data: state.Data.map((post) => { if(post.id === action.payload.postId) { const newLikedBy = {...post.LikedBy} // 删除对应的点赞记录 delete newLikedBy[action.payload.unlikeId] return { ...post, LikedBy: newLikedBy } } return post }), loading: false, } default: return state } }
3. 优化组件代码,删除无效的forceUpdate,优化点赞状态判断逻辑
postLiked = (id) => { this.props.onLikePost(this.props.user, id) } postUnliked = (id, unlikeID) => { this.props.onUnlikePost(id, unlikeID) } render() { return this.props.data.map((res) => { const liked = []; for(let key in res.LikedBy){ liked.push({ ...res.LikedBy[key], id: key }); } // 用some方法判断当前用户是否点赞,比filter更高效 const boolButton = liked.some(val => val.username === this.props.user) return( // 不要忘记给遍历生成的节点加唯一key <div key={res.id}> <div className="bottomButtons"> {boolButton ? <Button className="btn btn-primary likeDislike" id="likeButton" onClick={() => this.postUnliked(res.id, liked.find(val => val.username === this.props.user))} > <FontAwesomeIcon icon={faThumbsUp} style={{width:"13.5px", color:"white"}}/> </Button> : <Button className="btn btn-light likeDislike" id="likeButton" onClick={() => this.postLiked(res.id)} > <FontAwesomeIcon icon={faThumbsUp} style={{width:"13.5px"}}/> </Button> } </div> </div> ) }) }
内容的提问来源于stack exchange,提问作者Jashan
相关产品推荐
相关产品推荐

