Search code examples
reactjsfirebasegoogle-cloud-firestorereact-redux-firebase

What could cause React to re-render props such that Firebase query returns the wrong data?


My React Firebase app renders a series of posts that each render a list of comments:

PostList 
  PostSummary
    CommentList
      Comment

PostList and CommentList each query a different collection (e.g. "posts" and "comments") in Firebase. The query for CommentList should pull just those comments that match the post id of the parent.

Strangely, for every Post on the page, the comments match the database for only the last Post on the page. Through console.logs I've determined that at one point, the right comments are present in each CommentList, but for some reason the components re-render an additional time with the last PostSummary's post id regardless of which PostSummary is their parent.

How is it possible the CommentLists are accessing a postId that should not be in their props?

Components below

const PostList = (props) => {
  const { posts } = props

  return (
    <div>
        {posts && posts.map(post => {
          return (
            <PostSummary post={post} key={post.id} />
          )
        })}
    </div>
  )
}

const mapStateToProps = (state) => {
  return {
    posts: state.firestore.ordered.posts
  }
}

export default compose(
  connect(mapStateToProps),
  withRouter,
  firestoreConnect([
    { collection: 'posts',
      orderBy: ['created_At', 'desc'],
      limit: 3 }
  ])
)(FullPostList)
const PostSummary = ({ post }) => {
  //other code ommitted

    return (  
      <div className="flex">
        <div className="comments text-sm md:mx-0 mx-4 space-y-2">
          <CommentList postId={post.id} />
        </div>
      </div>
    )
}
const CommentList = (props) => {
  const { comments, postId } = props

  return (
    <ul>
      {comments && comments.map((comment,i) =>
        <Comment comment={comment} key={i} />
      )
      }
    </ul>
  )
}

const mapStateToProps = (state, ownProps) => {
  return {
    comments: state.firestore.ordered.comments
  }
}

export default compose(
  connect(mapStateToProps),
  withRouter,
  firestoreConnect(props => [
    { collection: 'comments',
      where: ['postId', '==', props.postId],
      orderBy: ['created_At', 'desc'] }
  ])
)(CommentList)

Solution

  • As Tarik pointed out, the issue was using the same redux store variable name for multiple different groups of comments at the same time. Easiest way around it seems to be dynamically naming each group of comments - so instead of state.firestore.ordered.comments, just do state.firestore.ordered[`${ownProps.recipeId}-comments`]

    Full solution:

    const CommentList = (props) => {
      const { comments, recipeId } = props
    
      return (
        <ul>
          {comments && comments.map((comment,i) =>
            <Comment comment={comment} key={i} />
          )
          }
        </ul>
      )
    }
    
    const mapStateToProps = (state, ownProps) => {
      return {
        comments: state.firestore.ordered[`${ownProps.recipeId}-comments`]
      }
    }
    
    export default compose(
      connect(mapStateToProps),
      withRouter,
      firestoreConnect(props => [
        {
          collection: 'comments',
          where: ['recipeId', '==', props.recipeId],
          orderBy: ['created_At', 'desc'],
          storeAs: `${props.recipeId}-comments`
        }
      ])
    )(CommentList)