You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

点击点赞/取消点赞按钮后如何让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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 21:45:00