Reactjs 即使在平面列表中呈现的组件声明为PureComponent且其props引用未更改,也会重新呈现它们
我正在使用redux开发一个react本机应用程序,在该应用程序中,我以页面的形式获取帖子,每个页面包含5篇帖子,并将它们呈现在一个平面列表中。当主屏幕呈现时,我获取文章的第一页,并在存储中使用空的posts数组将它们关联起来。当用户向下滚动时,我去获取下一页的帖子,并用posts数组将它们关联起来。问题是,在获取下一页文章并将其与现有文章数组关联时,我注意到已在平面列表中呈现的上一页中的现有文章会重新呈现。我通过登录componentDidUpdate生命周期方法检测到了这一点 以下是如何在主屏幕中呈现posts FlatList:Reactjs 即使在平面列表中呈现的组件声明为PureComponent且其props引用未更改,也会重新呈现它们,reactjs,react-native,redux,react-redux,immutability,Reactjs,React Native,Redux,React Redux,Immutability,我正在使用redux开发一个react本机应用程序,在该应用程序中,我以页面的形式获取帖子,每个页面包含5篇帖子,并将它们呈现在一个平面列表中。当主屏幕呈现时,我获取文章的第一页,并在存储中使用空的posts数组将它们关联起来。当用户向下滚动时,我去获取下一页的帖子,并用posts数组将它们关联起来。问题是,在获取下一页文章并将其与现有文章数组关联时,我注意到已在平面列表中呈现的上一页中的现有文章会重新呈现。我通过登录componentDidUpdate生命周期方法检测到了这一点 以下是如何在主
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 ) }
/>
);
}
}
/>
);
};
以下是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
,我希望现有的Post在以前和新的Post数组中具有相同的引用,因此它们不应该被重新引用。看起来您需要在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可以判断哪些项是新的,哪些是以前存在的。如果您使用FlatList
从RESTAPI呈现动态数据或分页数据,则不应将FlatList用作PureComponent。PureComponent不应该有状态,这就是为什么当道具改变时整个组件将被重新渲染的原因。您可以将Post
用作PureComponent,但不能在此处使用整个FlatList
。尝试一下,不要将FlatList
用作PureComponent。使用Post
作为PureComponent,组件Key
作为Key={positem.id}
当组件用作纯组件时,它不保持任何状态,在您的示例中,FlatList
为纯组件,因此一旦数据更改,它为该FlatList
调用render函数,并将其完全重新渲染。您是如何发现整个FlatList正在重新渲染的?我通过登录Post
componentHmm的componentdiddupdate lifecycle方法检测到,查看我的回答我回答说@KiranManiyaPureComponent不应该有状态
从什么时候开始?如果我不打算使用'FlatList',我应该使用什么?我不是说不使用FlatList,我是说使用FlatList作为有状态组件而不是纯状态组件。PureComponent确实有状态,但这里您不使用Post组件中的状态。使用FLatList作为有状态组件,使用状态而不是传递道具作为PureComponent发布。如果你还卡住了,告诉我。我将与大家分享这个代码片段,`FlatList`的`keyExtractor` prop负责将所需的`key` prop映射到`item`对象中的一个属性,在我的例子中,该属性是`id`。请参阅此项添加密钥是否没有任何区别?你发布的链接说,如果你不提供自定义的keyExtractor,那么默认的提取器会检查item.key,然后像React一样返回使用索引。
我已经提供了自定义的“keyExtractor”。请看我上面渲染的'FlatList'组件。
<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 ) }
/>