reactjs - 在 FlatList 中渲染的组件会被重新渲染,即使它们被声明为 PureComponent 并且它们的 props 引用没有改变
问题描述
我正在开发一个带有 redux 的 react native 应用程序,在该应用程序中,我将帖子作为页面获取,每个页面包含 5 个帖子并将它们呈现在 FlatList 中。当主屏幕呈现时,我获取帖子的第一页并将它们与商店中最初为空的帖子数组连接起来。当用户向下滚动时,我去获取下一页的帖子并将它们与帖子数组连接起来。问题是,在获取下一页帖子并将它们与现有帖子数组连接时,我注意到已经在 FlatList 中呈现的先前页面中的现有帖子被重新呈现。我通过登录 componentDidUpdate 生命周期方法检测到这一点。
这是我在主屏幕中呈现帖子 FlatList 的方式:
renderPostsList = () => {
const { posts, onFetchPosts, postsComments } = this.props;
return(
<FlatList
style = { styles.postsList }
keyExtractor = { item => item.id.toString() }
onEndReachedThreshold = { 0.5 }
onEndReached = { ({distanceFromEnd}) => { onFetchPosts() } }
data = { posts }
renderItem = { ({ item }) => {
return(
<Post
userName = { item.user.username }
time = { item.created_at }
content = { item.onlyText }
commentsCount = { item.commentCount }
likesCount = { item.likeCount }
dislikesCount = { item.dislikeCount }
sharesCount = { item.shareCount }
comments = { postsComments.get( item.id ) }
fetchCommentsHandler = { this.getFetchCommentsHandlerForPost( item ) }
/>
);
}
}
/>
);
};
这是getFetchCommentsHandlerForPost
方法:
getFetchCommentsHandlerForPost = post => {
return () => {
if ( post.commentCount > 0 ) {
this.props.onFetchComments( post.id );
}
};
};
这是onFetchPosts
动作创建者:
export const fetchPosts = () => ( dispatch, getState ) => {
const { nextPage } = getState().posts;
if ( !nextPage ) {
return;
}
dispatch( startLoading() );
const user = getState().auth.user.user;
const userId = user
? user.id
: null;
axios( '/posts', {
method: 'GET',
params: {
userId,
page: nextPage
}
} )
.then( res => {
const posts = res.data.data.map( item => {
if ( !item.user ) {
item.user = { username: 'No Name' };
}
return item;
} );
dispatch( appendPosts( posts ) );
const { current_page, last_page } = res.data.meta;
const nextPage = current_page === last_page? null : current_page + 1;
dispatch( updateNextPage( nextPage ) );
dispatch( stopLoading() );
} )
.catch( err => {
dispatch( stopLoading() );
dispatch( setError( i18n.t( 'errors.fetch_posts_failed' ) ) )
} );
};
这是帖子减速器:
import { APPEND_POSTS,
START_LOADING,
STOP_LOADING,
POSTS_SET_ERROR,
POSTS_CLEAR_ERROR,
UPDATE_NEXT_PAGE } from '../actions/ActionTypes';
const initialState = {
posts: [],
nextPage: 1,
isLoading: false,
error: null
};
const postsReducer = ( state = initialState, action ) => {
switch( action.type ) {
case APPEND_POSTS:
return {
...state,
posts: state.posts.concat( action.payload.posts )
};
case UPDATE_NEXT_PAGE:
return {
...state,
nextPage: action.payload.nextPage
};
case START_LOADING:
return {
...state,
isLoading: true
};
case STOP_LOADING:
return {
...state,
isLoading: false
};
case POSTS_SET_ERROR:
return {
...state,
error: action.payload.error
};
case POSTS_CLEAR_ERROR:
return {
...state,
error: null
};
default:
return state;
}
};
export default postsReducer;
由于 FlatList 和我的Post
组件都是PureComponent
,我希望现有帖子在以前的和新的帖子数组中具有相同的引用,因此它们不应该被重新渲染。
解决方案
看起来您需要在 s 中添加key
一个Post
:
<Post
key = {item.id}
userName = { item.user.username }
time = { item.created_at }
content = { item.onlyText }
commentsCount = { item.commentCount }
likesCount = { item.likeCount }
dislikesCount = { item.dislikeCount }
sharesCount = { item.shareCount }
comments = { postsComments.get( item.id ) }
fetchCommentsHandler = { this.getFetchCommentsHandlerForPost( item ) }
/>
现在 React 可以分辨哪些项目是新的,哪些是以前的。
推荐阅读
- docker - 使用 Docker swarm 和 windows 容器暴露端口的问题
- laravel - 如何修复 Laravel 8 Sanctum 和 VueJS 3 的“401 Unauthorized”错误?
- aspnetboilerplate - Abp.io 中 IShouldNormalize 的替代方案是什么?
- c# - 如何为多个属性重用多个数据注释
- hibernate - 在 Play 1.x 中设置自定义 Hibernate 会话范围的拦截器不起作用
- python - 从具有不同模式的字符串中提取特定信息
- python - 我如何让机器人只通过输入不带标签的用户名来提及某人
- apache-spark - 在单个节点上运行 Spark 作业
- python - 逐步添加到列表
- docker - 如何创建至少具有相同开放端口的 docker 容器?