是什么导致 React 重新渲染 props,导致 Firebase 查询 returns 错误的数据?
What could cause React to re-render props such that Firebase query returns the wrong data?
我的 React Firebase 应用呈现一系列 post,每个呈现评论列表:
PostList
PostSummary
CommentList
Comment
PostList 和 CommentList 在 Firebase 中各自查询不同的集合(例如“posts”和“comments”)。对 CommentList 的查询应该只提取那些与父级的 post id 相匹配的评论。
奇怪的是,对于页面上的每个 Post,评论仅与页面上最后一个 Post 的数据库匹配。通过 console.logs 我确定在某一点上,每个 CommentList 中都存在正确的评论,但由于某种原因,组件会重新呈现最后一个 Post 摘要的 post 的额外时间id 不管哪个 PostSummary 是它们的父级。
CommentLists 怎么可能访问一个 post不应该出现在他们的 prop 中的 ID?
以下组件
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)
这里的问题在redux
。我不熟悉您使用的库,但据我所知,它在 redux 存储中的 post 下存储了每个 posts
,在 redux 存储中的评论下存储了每个 comments
。因此,每次您获得 comments
的集合时,它都会保存在与之前的集合相同的位置并覆盖它。这就是为什么你总是看到最后 post.
的评论的原因
在该库的文档中,我找不到任何类型的 alias
集合。
您可以重构数据库结构以将 comments
存储在 comments/postUid
之类的路径下,然后像这样读取它们:
firestoreConnect(props => [
{ collection: `comments/${props.postId}`,
orderBy: ['created_At', 'desc'] }
])
或者使用支持 aliasing
集合的库,或者直接使用 firebase SDK。
Here 是没有 redux 的 Provider
解决方案,它将支持您的数据库结构并且可以使用 aliasing
.
正如 Tarik 所指出的,问题在于同时对多个不同的评论组使用相同的 redux 存储变量名称。最简单的解决方法似乎是动态命名每组评论 - 所以不用 state.firestore.ordered.comments
,只需 state.firestore.ordered[`${ownProps.recipeId}-comments`]
完整解决方案:
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)
我的 React Firebase 应用呈现一系列 post,每个呈现评论列表:
PostList
PostSummary
CommentList
Comment
PostList 和 CommentList 在 Firebase 中各自查询不同的集合(例如“posts”和“comments”)。对 CommentList 的查询应该只提取那些与父级的 post id 相匹配的评论。
奇怪的是,对于页面上的每个 Post,评论仅与页面上最后一个 Post 的数据库匹配。通过 console.logs 我确定在某一点上,每个 CommentList 中都存在正确的评论,但由于某种原因,组件会重新呈现最后一个 Post 摘要的 post 的额外时间id 不管哪个 PostSummary 是它们的父级。
CommentLists 怎么可能访问一个 post不应该出现在他们的 prop 中的 ID?
以下组件
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)
这里的问题在redux
。我不熟悉您使用的库,但据我所知,它在 redux 存储中的 post 下存储了每个 posts
,在 redux 存储中的评论下存储了每个 comments
。因此,每次您获得 comments
的集合时,它都会保存在与之前的集合相同的位置并覆盖它。这就是为什么你总是看到最后 post.
在该库的文档中,我找不到任何类型的 alias
集合。
您可以重构数据库结构以将 comments
存储在 comments/postUid
之类的路径下,然后像这样读取它们:
firestoreConnect(props => [
{ collection: `comments/${props.postId}`,
orderBy: ['created_At', 'desc'] }
])
或者使用支持 aliasing
集合的库,或者直接使用 firebase SDK。
Here 是没有 redux 的 Provider
解决方案,它将支持您的数据库结构并且可以使用 aliasing
.
正如 Tarik 所指出的,问题在于同时对多个不同的评论组使用相同的 redux 存储变量名称。最简单的解决方法似乎是动态命名每组评论 - 所以不用 state.firestore.ordered.comments
,只需 state.firestore.ordered[`${ownProps.recipeId}-comments`]
完整解决方案:
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)