简体   繁体   中英

Redux store is updated but UI is not

I'm having an issue with my vote score on comments. I can see in Redux Devtool that the value has changed but I need to force reload to update the UI.

Not sure why this is. I get my comments as an object with a key of the parent elements id as a key and an array inside of it.

This is then converted inside of mapStateToProps.

Heres an image showing different stages of comments.

在此处输入图片说明

Anyone have any idea why this is.

Cheers, Petter


Action

export function pushVoteComment(option, postId) {
  const request = API.commentPostVote(option, postId)

  return dispatch => {
    request.then(({ data }) => {
      dispatch({ type: COMMENTS_POST_VOTE, payload: data, meta: postId })
    })
  }
}

Reducer

const comments = (state = {}, action) => {
  switch (action.type) {
    case COMMENTS_GET_COMMENTS:
      return {
        ...state,
        [action.meta]: action.payload,
      }
    case COMMENTS_POST_VOTE:
      console.log('An vote request was sent returning ', action.payload)
      return { ...state, [action.payload.id]: action.payload }
    default:
      return state
  }
}

PostDetailes ( its used here to render a PostComment )

renderComments() {
    const { comments, post } = this.props
    console.log('This post has these comments: ', comments)
    return _.map(comments, comment => {
      return (
        <div key={comment.id} className="post-container">
          {post ? (
            <PostComment
              key={comment.id}
              postId={comment.id}
              body={comment.body}
              author={comment.author}
              voteScore={comment.voteScore}
              timestamp={comment.timestamp}
            />
          ) : (
            ''
          )}
        </div>
      )
    })
  }

const mapStateToProps = (state, ownProps) => {
  const { posts, comments } = state
  return {
    comments: comments[ownProps.match.params.postId],
    post: posts.filter(
      item => item.id === ownProps.match.params.postId && item.deleted !== true
    )[0],
  }
}

PostComment

  <i
    className="fa fa-chevron-up"
    aria-hidden="true"
    onClick={() => pushVoteComment('upVote', postId)}
  />
  <span className="vote-amount">{voteScore}</span>
  <i
    className="fa fa-chevron-down"
    onClick={() => pushVoteComment('downVote', postId)}
  />

export default connect(null, { pushVoteComment })(PostComment)

PS:

The reason it is built with a {parentId: [{comment1}, {comment2}]}

Is that I use it when showing all posts to see a number of comments.

return ({comments.length})

const mapStateToProps = (state, ownProps) => {
  return {
    comments: state.comments[ownProps.postId]
      ? state.comments[ownProps.postId]
      : [],
  }
}

Redux dev tool

Looks like this when I press the votebutton for the first time:

在此处输入图片说明

Then when I press again I get this:

在此处输入图片说明

The issue here is that it's changing the state, not thinking about the fact that I have my comment stored as

{
  [postId]: [array of comments]
}

So in order to resolve it, I ended up rewriting my reducer doing it like this.

case COMMENTS_POST_VOTE:
  const { parentId } = action.payload // get commentId
  const commentList = [...state[parentId]] // get array of comments, but copy it
  const commentIndex = commentList.findIndex(el => (el.id === payload.id)) // get index of comment
  commentList[commentIndex] = action.payload // update the commentList
  const updatedPost = {...state, [parentId]: commentList} // return new state
  return updatedPost

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM