gpt4 book ai didi

javascript - "VirtualizedList: You have a large list that is slow to update"警告即使所有组件都已优化

转载 作者:行者123 更新时间:2023-12-05 00:26:12 26 4
gpt4 key购买 nike

在使用 <FlatList> 时,我在尝试避免收到“VirtualizedList: You have a large list that is slow to update”警告时遇到了很多麻烦。带有 React-Native 的组件。
我已经做了大量的研究和 Google-Fu 来尝试一个解决方案,但是没有一个解决方案有帮助,甚至没有 this GitHub issue 上的解决方案。 .
要记住的事情:

  • 我正在使用 shouldComponentUpdate() { return false; }在我的列表项组件中,因此它们根本没有更新。
  • 呈现 FlatList 的组件已经是 PureComponent
  • 我在组件的渲染方法中添加了 console.logs,并且可以确认它们不会重新渲染。
  • 我没有使用匿名函数,所以 renderItem组件不会在每次调用时重新初始化。

  • 重要 : 只有在使用我的 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>
    );
    };
    目录屏幕.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",
    }
    });

    由于我的组件和列表已优化并且我仍然收到错误,我开始相信这可能是 React Native 的实际问题 - 但如果有人能看到我做错了什么或任何解决方法,这个会有很大帮助!
    其他发现:
    我发现如果 CatalogScreen 不再出现警告组件包含在 NativeStackNavigator 中与一个单一的屏幕。我相信这可能表明这是 BottomTabNavigator 的问题。模块。
    例如,如果我进行以下更改,则不再出现警告:
    应用程序.tsx
    const AppRoutes = [
    { name: "Home", Component: HomeScreen },
    { name: "Catalog", Component: CatalogPage }, // Changed CatalogScreen to CatalogPage
    { name: "Cart", Component: CartScreen }
    ];
    目录屏幕.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>
    );
    }
    }
    使用此解决方法,我将呈现堆栈导航组件而不是 CatalogScreen直接组成。这解决了问题,但我不明白为什么这会有所作为。与 BottomTabNavigator 屏幕相比,React Native 在 Stack Navigation 屏幕中处理内存对象的方式是否不同?

    最佳答案

    我只是随机回答一个问题,但充其量只是一个猜测。
    您在评论中链接到您的问题的视频使发生的事情更加清楚,那里发生了一些奇怪的事情。
    对于像这样的普通列表,尤其是在移动设备上,您只想渲染和加载当前正在显示和可见的项目,您不想将所有可能项目的整个列表保留在内存中并一直渲染。这就是为什么你会使用回调之类的东西来呈现项目,以便列表可以在滚动时调用回调并只呈现它需要的项目。
    这里说的是我能想到的一些随机的事情:

  • 确保每个组件,尤其是 item 组件,都是纯组件,因此它们不会重新渲染。确保项目组件不会再次呈现。
  • 尝试更改您的 Prop 解构,以便您直接接收 Prop ,即({prop1, prop2})而不是 props...props .如果您像这样解构 Prop ,它将在每次加载项目时创建一个新对象。如果平面列表不断调用回调并创建大量新对象,这可能是导致您的问题的罪魁祸首之一。这也可能是产品项目的一个问题,如果它看到它收到了一个新的 Prop 引用,这意味着它是一个不同的对象,那么它将不得不做一个浅层比较(即使它是一个纯组件),数百的 Prop 。那真的可以减慢它的速度。结果是它实际上不会重新渲染它,但它仍然会进行数百次浅对象比较,这是一个缓慢的过程。所以修复解构,我敢打赌这样的事情会导致性能问题。
  • 确保不要双重渲染 View ,不要在实际加载数据之前渲染平面列表,在设置状态之前只返回回退微调器或加载器,一旦设置了状态,然后返回完整的 child .否则,即使没有数据,您也会双重渲染整个事物。
  • 如果您使用匿名函数作为 renderItem 回调,而不是使用 react 类函数,请尝试看看是否会有所不同。我不认为它应该有所作为,但如果没有其他帮助的话还是值得一试的,因为我不确定 renderItem 如何使用 this .

  • 如果一切都失败了,我建议你在 github 上询问 react native,同时尝试使用替代方案(如果有的话)。另一方面,我并没有真正从视频中看到任何性能问题,所以也许这也是一个可以安全忽略的错误。

    关于javascript - "VirtualizedList: You have a large list that is slow to update"警告即使所有组件都已优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70059668/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com