Jor*_*ldt 11 javascript typescript reactjs react-native
在使用 React-Native 组件时,我在尝试避免收到“VirtualizedList:您有一个更新缓慢的大列表”警告时遇到了很多麻烦<FlatList>。
我已经做了大量的研究和 Google-Fu 来尝试解决方案,但没有一个解决方案有帮助,甚至这个 GitHub 问题上的解决方案也没有帮助。
要记住的事情:
shouldComponentUpdate() { return false; },因此它们根本不更新。PureComponentrenderItem组件不会在每次调用时重新初始化。重要提示:该警告似乎仅在使用 my 切换到单独的选项卡BottomTabNavigator然后返回并滚动浏览我的列表后才会出现;但这很令人困惑,因为当我这样做时,FlatList 屏幕组件不会重新渲染,列表项也不会重新渲染。由于浏览到另一个选项卡时组件不会重新渲染,为什么会发生此错误?
这是我的确切代码:
应用程序.tsx
const AppRoutes = [
{ name: "Home", Component: HomeScreen },
{ name: "Catalog", Component: CatalogScreen },
{ name: "Cart", Component: CartScreen }
];
export const StoreApp = () => {
return (
<NavigationContainer>
<StatusBar barStyle="dark-content" />
<Tabs.Navigator>
{AppRoutes.map((route, index) =>
<Tabs.Screen
key={index}
name={route.name}
component={route.Component}
options={{
headerShown: (route.name !== "Home") ?? false,
tabBarIcon: props => <TabIcon icon={route.name} {...props} />
}}
/>
)}
</Tabs.Navigator>
</NavigationContainer>
);
};
Run Code Online (Sandbox Code Playgroud)
目录屏幕.tsx
import React from "react";
import { FlatList, SafeAreaView, Text, View, StyleSheet } from "react-native";
import { LoadingSpinnerOverlay } from "../components/LoadingSpinnerOverlay";
import { getAllProducts, ProductListData } from "../api/catalog";
class ProductItem extends React.Component<{ item: ProductListData }> {
shouldComponentUpdate() {
return false;
}
render() {
return (
<View>
{console.log(`Rendered ${this.props.item.name}-${Math.random()}`)}
<Text style={{height: 100}}>{this.props.item.name}</Text>
</View>
);
}
}
export class CatalogScreen extends React.PureComponent {
state = {
productData: []
};
componentDidMount() {
getAllProducts()
.then(response => {
this.setState({ productData: response.data });
})
.catch(err => {
console.log(err);
});
}
private renderItem = (props: any) => <ProductItem {...props} />;
private keyExtractor = (product: any) => `${product.id}`;
private listItemLayout = (data: any, index: number) => ({
length: 100,
offset: 100 * index,
index
});
render() {
const { productData } = this.state;
console.log("CATALOG RENDERED");
return (
<SafeAreaView style={styles.pageView}>
{!productData.length && <LoadingSpinnerOverlay text="Loading products..." />}
<View style={{backgroundColor: "red", height: "50%"}}>
<FlatList
data={productData}
removeClippedSubviews
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
getItemLayout={this.listItemLayout}
/>
</View>
</SafeAreaView>
);
}
};
const styles = StyleSheet.create({
pageView: {
height: "100%",
position: "relative",
}
});
Run Code Online (Sandbox Code Playgroud)
由于我的组件和列表已经过优化,但我仍然收到错误,我开始相信这可能是 React Native 的实际问题 - 但如果有人能看到我做错了什么,或者有任何解决方法,这会有很大帮助!
其他发现:CatalogScreen我发现如果组件包含在NativeStackNavigator单个屏幕内
,则不再出现警告。我相信这可能表明这是模块的问题BottomTabNavigator。
例如,如果我进行以下更改,则不会再出现警告:
应用程序.tsx
const AppRoutes = [
{ name: "Home", Component: HomeScreen },
{ name: "Catalog", Component: CatalogPage }, // Changed CatalogScreen to CatalogPage
{ name: "Cart", Component: CartScreen }
];
Run Code Online (Sandbox Code Playgroud)
目录屏幕.tsx
const Stack = createNativeStackNavigator();
export class CatalogPage extends React.PureComponent {
render() {
return (
<Stack.Navigator>
<Stack.Screen
name="CatalogStack"
options={{ headerShown: false }}
component={CatalogScreen}
/>
</Stack.Navigator>
);
}
}
Run Code Online (Sandbox Code Playgroud)
通过此解决方法,我将渲染堆栈导航组件而不是CatalogScreen直接渲染该组件。这解决了问题,但我不明白为什么这会产生影响。React Native 在 Stack Navigation 屏幕中处理内存对象的方式与 BottomTabNavigator 屏幕中的内存对象不同吗?
小智 1
我只是随机地给出一个答案,但这充其量只是一个猜测。
您在评论中链接到您的问题的视频使发生的事情更加清楚,那里发生了一些奇怪的事情。
对于像这样的普通列表,尤其是在移动设备上,您只想渲染和加载当前正在显示和可见的项目,您不希望将所有可能项目的整个列表保留在内存中并始终渲染。这就是为什么您要使用回调之类的东西来呈现项目,以便列表可以在滚动时调用回调并仅呈现它需要的项目。
话虽如此,这里有一些我能想到的随机事情:
({prop1, prop2})不是props使用...props. 如果你像这样解构 props,它会在每次加载项目时创建一个新对象。如果平面列表不断调用回调并创建大量新对象,这可能是导致问题的罪魁祸首之一。这也可能是产品项目的一个问题,如果它发现它收到了一个新的 prop 引用,这意味着它是一个不同的对象,那么它必须对数百个进行浅层比较(即使它是纯组件)道具。这确实会减慢速度。结果是它实际上不会重新渲染它,但它仍然会进行数百次浅层对象比较,这是一个缓慢的过程。因此,修复解构,我敢打赌这样的事情会导致性能问题。this.如果一切都失败了,我建议你在 github 上询问 React Native,同时尝试使用替代方案(如果有)。另一方面,我并没有真正从视频中看到任何性能问题,所以也许这也是一个可以安全忽略的错误。
| 归档时间: |
|
| 查看次数: |
8609 次 |
| 最近记录: |