【问题标题】:Updating deeply nested state in Redux在 Redux 中更新深度嵌套的状态
【发布时间】:2019-06-02 12:39:46
【问题描述】:

我正在更新我所做的“留言板”项目(Brad Traversy 的 MERN 堆栈课程),以包含点赞评论。举个简单的例子,想想 Facebook:你创建一个人们可以喜欢的帖子,人们可以用 cmets 回复,这也可以被喜欢。

我有一个“帖子”状态,其中包含帖子喜欢(post.likes 数组)、cmets(post.cmets 数组)和评论喜欢(事情变得棘手:嵌套在 post.cmets 数组中的数组)。

如何更新 reducer 中的嵌套数组,以便我的页面正确重新呈现?现在,它会记录操作并在手动重新加载页面时显示新的喜欢/不喜欢,但它不会重新加载页面本身。

我尝试过更新状态,但事实是,我不完全确定如何循环并更新深度嵌套的内容。

这是我的实际帖子状态,由 Redux DevTools 提供。

post: {
    posts: [],
    post: {
      _id: '5cebd8bcdc17fd5cd7e57a45',
      text: 'This is my brand new post.',
      name: 'Bobby Smith',
      avatar: '//www.gravatar.com/avatar/414868368393e3ba8ae5ff93eeb98de6?s=200&r=pg&d=mm',
      user: '5cd646c9a632b51373121995',
      likes: [
        {
          _id: '5cebd8d1dc17fd5cd7e57a47',
          user: '5cd36ce5fda120050ee64160'
        }
      ],
      comments: [
        {
          date: '2019-05-27T12:32:16.172Z',
          likes: [ /*-------- This ---------*/
            {
              _id: '5cebd8e1dc17fd5cd7e57a48',
              user: '5cd646c9a632b51373121995'
            }
          ],
          _id: '5cebd8d0dc17fd5cd7e57a46',
          text: 'And this is my brand new response.',
          name: 'John Doe',
          avatar: '//www.gravatar.com/avatar/b2b146dba9e0023cb56637f0df4aa005?s=200&r=pg&d=mm',
          user: '5cd36ce5fda120050ee64160'
        }
      ],
      date: '2019-05-27T12:31:56.598Z',
      __v: 3
    },
    loading: false,
    error: {}
  }
}

减速机:

const initialState = {
  posts: [],
  post: null,
  loading: true,
  error: {}
}

export default function(state = initialState, action) {
  const { type, payload } = action
  switch (type) {
    case UPDATE_COMMENT_LIKES:
      return {
        ...state,
        post: { ...state.post, comments: ???? }
      }
    default:
      return state
  }
}

它传入post ID和user ID,然后根据它们是否已经存在进行过滤。为了清楚起见,我还将添加动作创建者。

// Add like to comment
export const addCommentLike = id => async dispatch => {
  try {
    const res = await axios.put(`/api/posts/comment/like/${id}`)

    dispatch({
      type: UPDATE_COMMENT_LIKES,
      payload: { id, likes: res.data }
    })
  } catch (err) {
    dispatch({
      type: POST_ERROR,
      payload: { msg: err.response.statusText, status: err.response.status }
    })
  }
}

// Remove like from comment
export const removeCommentLike = id => async dispatch => {
  try {
    const res = await axios.put(`/api/posts/comment/unlike/${id}`)

    dispatch({
      type: UPDATE_COMMENT_LIKES,
      payload: { id, likes: res.data }
    })
  } catch (err) {
    dispatch({
      type: POST_ERROR,
      payload: { msg: err.response.statusText, status: err.response.status },
      loading: false
    })
  }
}

现在,它正在更新数据库中的所有内容,但不会立即更新状态并触发重新渲染。

如果能得到任何帮助,我将不胜感激。

谢谢!

【问题讨论】:

标签: reactjs redux react-redux


【解决方案1】:

我知道这有点太晚了,但它可能对某人有所帮助。顺便说一句,我也上了这门课;) 所以在你的情况下减速器看起来像这样:

case UPDATE_COMMENT_LIKES:
  return {
    ...state,
    post: {
      ...state.post,
      comments: state.post.comments.map((comment) =>
        comment._id === payload.id
          ? { ...comment, likes: payload.likes }
          : comment
      )
    },
    loading: false
  };

【讨论】:

    【解决方案2】:

    如果你也能在你的 reducer 中拆分删除/添加逻辑会更好:

    • ADD_COMMENT_LIKES - 将喜欢添加到嵌套的喜欢数组中
    • REMOVE_COMMENT_LIKES - 将根据 id 过滤选择的like
    export default function(state = initialState, action) {
    
        const { type, payload } = action;
    
        switch (type) {
            case ADD_COMMENT_LIKES:
                return {
                    ...state,
                    post: {
                        ...state.post,
                        comments: [
                            ...state.post.comments,
                            likes: [
                                ...state.post.comments.likes,
                                payload <--- inserting the new like
                            ]
                        ]
                    }
                }
            case REMOVE_COMMENT_LIKES:
                return {
                    ...state,
                    post: {
                        ...state.post,
                        comments: [
                            ...state.post.comments,
                            likes: [
                                ...state.post.comments.likes.filter((item) => item.id !== payload.id)
                            ]
                        ]
                    }
            default:
                return state
        }
    }
    

    阅读如何combine reducers,并将您的状态形成为一个独立的分支。它将帮助您以更易于维护的结构构建您的减速器。

    【讨论】:

    • 谢谢!我暂时保留“UPDATE_COMMENT_LIKES”,但稍后会更改它(我还是新手,所以每次更改都需要很长时间)。当我尝试执行以下操作时: [ ...payload ] 位,它返回一个错误并说“...payload”是一个意外的标记。 “likes”是一个对象数组是否有区别,所以它会被访问类似于 state.post.cmets[0].likes...?
    • @PalmettoStater - 这取决于您从 API 获得的响应。尝试检查res.data 的值。
    • 我得到一个看起来像这样的对象:{ _id: '5cebd8d1dc17fd5cd7e57a47', user: '5cd36ce5fda120050ee64160' }
    • 你得到的对象是更新(删除/添加)之类的。这是您从axios 返回的响应对象,表示更新已成功完成。现在,如果您将在我的回答中使用减速器,它应该根据需要加入/过滤更新的对象。
    • 如果您想要更新 like 数组的新版本,而无需按照我的回答中所述的用于添加/删除的单独减速器逻辑,您将需要另一个操作并调用 API 来获取评论数据,并在商店中更新此评论 likes 数组。
    猜你喜欢
    • 2021-03-15
    • 2016-06-27
    • 1970-01-01
    • 1970-01-01
    • 2019-04-28
    • 2021-11-01
    • 2021-04-15
    • 1970-01-01
    • 2017-08-08
    相关资源
    最近更新 更多