React-Native 另一个 VirtualizedList 支持的容器

Posted

技术标签:

【中文标题】React-Native 另一个 VirtualizedList 支持的容器【英文标题】:React-Native another VirtualizedList-backed container 【发布时间】:2020-02-03 05:19:36 【问题描述】:

升级到 react-native 0.61 后,我收到很多这样的警告:

VirtualizedLists should never be nested inside plain ScrollViews with the same orientation - use another VirtualizedList-backed container instead.

我应该使用的另一个VirtualizedList-backed container 是什么,为什么现在建议不要那样使用?

【问题讨论】:

您能否为您的问题提供完整的警告信息?因为用你现在的标题很难找到。 仅针对可能遇到与我相同问题的任何人,这是因为我将<FlatList />封装在<ScrollView /> 如果 FlatList 中没有更多项目,只需在 ScrollView 内渲染项目而不使用 FlatList 【参考方案1】:

如果有人仍在寻找关于 @Ponleu 和 @David Schilling 在这里描述的问题的建议(关于 FlatList 上方的内容),那么这就是我采取的方法:

<SafeAreaView style=flex: 1>
    <FlatList
      data=data
      ListHeaderComponent=ContentThatGoesAboveTheFlatList
      ListFooterComponent=ContentThatGoesBelowTheFlatList />
</SafeAreaView>

您可以在此处阅读更多信息:https://facebook.github.io/react-native/docs/flatlist#listheadercomponent

希望它可以帮助某人。 :)

【讨论】:

你知道为什么这应该比产生警告的方式更好吗? @DavidSchilling 因为您尝试使用 2 个滚动容器的结果的方式:ScrollViewFlatList - 您将获得不一致的滚动行为。此答案中提出的方式仅产生 1 个滚动容器,并且在页眉/页脚中,您可以放置​​任何视图,无论多么复杂。 我正在使用函数组件,并遇到 ContentThatGoesAboveTheFlatList 重新渲染问题。对此的任何解决方案 @Ponleu 您可以使用 React 提供的 useMemo 挂钩来记忆您的 ContentThatGoesAboveTheFlatList 组件,以避免重新渲染。更多信息在这里:reactjs.org/docs/hooks-reference.html#usememo 如果有帮助,请告诉我。 :) 我需要在一个页面中包含两个包含不同数据集的平面列表...我该怎么办?【参考方案2】:

以防万一这对某人有所帮助,这就是我在我的案例中修复错误的方法。

我有一个 FlatList 嵌套在 ScrollView 中:

render() 
    return (
        <ScrollView>
            <Text>'My Title'</Text>
            <FlatList
                data=this.state.myData
                renderItem=( item ) => 
                    return <p>item.name</p>;
                
            />
            this.state.loading && <Text>'Loading...'</Text>
        </ScrollView>
    );

我摆脱了ScrollView,使用FlatList 渲染我需要的一切,从而摆脱了警告:

render() 
    const getHeader = () => 
        return <Text>'My Title'</Text>;
    ;

    const getFooter = () => 
        if (this.state.loading) 
            return null;
        
        return <Text>'Loading...'</Text>;
    ;

    return (
        <FlatList
            data=this.state.myData
            renderItem=( item ) => 
                return <p>item.name</p>;
            
            ListHeaderComponent=getHeader
            ListFooterComponent=getFooter
        />
    );

【讨论】:

致寻找最佳答案的人:“选择这个。仅使用一个 FlatList。”【参考方案3】:

最好的方法是禁用该警告,因为有时Flatlist 需要在ScrollView 中。

更新 RN V0.63 以上

YellowBox 现在已更改并替换为 LogBox

功能性

import React,  useEffect  from 'react';
import  LogBox  from 'react-native';

useEffect(() => 
    LogBox.ignoreLogs(['VirtualizedLists should never be nested']);
, [])

基于类

import React from 'react';
import  LogBox  from 'react-native';

componentDidMount() 
    LogBox.ignoreLogs(['VirtualizedLists should never be nested']);

在下面更新 RN V0.63

功能性

import React,  useEffect  from 'react';
import  YellowBox  from 'react-native';

useEffect(() => 
    YellowBox.ignoreWarnings(['VirtualizedLists should never be nested']);
, [])

基于类

import React from 'react';
import  YellowBox  from 'react-native';

componentDidMount() 
    YellowBox.ignoreWarnings(['VirtualizedLists should never be nested']);

【讨论】:

我有一个打开对话框的按钮,其中有一个输入框。当我单击输入时,对话框立即消失。所以我不得不用 ScrollView 包装 FlatList。那正在解决问题,但会导致警告。我发现的解决方案都没有奏效。所以在这种情况下,我完全同意尼沙格的观点。如果有人找到解决方案,请通知我。 这似乎是我唯一的方法,没有其他建议可以帮助我,使用除了滚动视图之外的其他组件是行不通的! 你知道,警告是有原因的,你不应该忽略它们...... 同意,但有时我们需要因为一些低版本的依赖关系 @RafaelTavares,那么为什么这些被忽略的函数存在呢?【参考方案4】:

出现警告是因为ScrollViewFlatList 共享相同的逻辑,如果FlatListScrollView 中运行,则会重复

顺便说一下SafeAreaView对我不起作用,唯一的解决方法是

<ScrollView>
    data.map((item, index) => 
        ...your code
    
</ScrollView>

错误消失

【讨论】:

这个对我有用。我需要在 Scrollview 中的 Flatlist 和你在这里建议的旧的 map 函数为我做了它! 不明白这个。地图有什么帮助? FlatList 去哪儿了? 想法正确,但代码不起作用。【参考方案5】:

查看文档中的示例,我已从以下位置更改容器:

<ScrollView>
    <FlatList ... />
</ScrollView>

到:

<SafeAreaView style=flex: 1>
    <FlatList ... />
</SafeAreaView>

所有这些警告都消失了。

【讨论】:

如果我将内容呈现在FlatList 内部ScrollView 并希望该内容可滚动? 两个可滚动的视图并排放置并不是很好的用户体验。我会尝试像这样嵌套它:''(未测试) 我和@Ponleu 有同样的问题。我在一些内容里面有一个ScrollView,然后在ScrollView 里面还有一个FlatList。我希望整个屏幕一起滚动。 &lt;SafeAreaView&gt; 仅适用于 ios 11 或更高版本 (facebook.github.io/react-native/docs/safeareaview) ScrollView 的主要目的是让它可以垂直滚动。获取该属性不会使其再次可滚动。这里有什么意义?【参考方案6】:

解决方案 #1

// dummy data array
const data = [
    id: 1, name: 'Tom',
    id: 2, name: 'Jerry',
]

你也可以像这样为它制作一个自定义组件

const VirtualizedList = (children) => 
    return (
        <FlatList
            data=[]
            keyExtractor=() => "key"
            renderItem=null
            ListHeaderComponent=
                <>children</>
            
        />
    )

然后使用这个 VirtualizedList 作为父组件:

...
return (
    <VirtualizedList>
         <FlatList
           data=data
           keyExtractor=(item, index) => item.id + index.toString()
           renderItem=_renderItem
         />
         <AnyComponent/>
    </VirtualizedList>
)

解决方案 #2

如果您在 ScrollView 中使用 FlatList,它会发出令人讨厌的警告,因此您可以像这样使用数组的 map 属性 -

<ScrollView>
    data.map((item, index) => (
        <View key=index>
           <Text>item.name</Text>
        </View>
    ))
</ScrollView>

解决方案 #3

如果您将 FlatList 设为水平(根据您的需要),那么警告也会消失

<ScrollView>
    <FlatList
       data=data
       keyExtractor=(item, index) => item.id + index.toString()
       horizontal=true
    />
</ScrollView>

解决方案 #4

可以添加页眉和页脚组件

在 ListHeaderComponent 和 ListFooterComponent 中你可以添加任何组件,这样你就不需要父 ScrollView

<FlatList
   data=data
   keyExtractor=(item, index) => item.id + index.toString()
   ListHeaderComponent=headerComponent
   ListFooterComponent=footerComponent
   ListEmptyComponent=emptyComponent
   ItemSeparatorComponent=separator
/>

// List components
const headerComponent = () => (
    <View>
       <Header/>
       <Any/>
    </View>
)
const footerComponent = () => (
    <View>
       <Footer/>
       <Any/>
    </View>
)
const emptyComponent = () => (
    <View>
       <EmptyView/>
       <Any/>
    </View>
)
const separator = () => (
    <View style=height: 0.8, width: '100%', backgroundColor: '#fff' />
)

【讨论】:

FlatList 通常用于动态加载和显示数据。在大多数情况下,将其转换为静态列表并不是一种方法。 它工作得很好,可能是你做错了什么。 在我的情况下,horizo​​ntal=false 成功了,因为水平=true 将导致 FlatList 水平渲染项目,这是没人想要的... 正如我上面所说,根据您的要求将其设置为horizo​​ntal=true。【参考方案7】:

在 my case 中,我需要将 FlatLists 嵌套在 ScrollView 中,因为我使用 react-native-draggable-flatlist 在配方中移动成分和步骤。

如果我们正确阅读警告,它说我们应该使用另一个 VirtualizedList 支持的容器来嵌套我们的子 FlatList。我所做的是:

 /* outside the component */
const emptyArry = []

/* render */
 <FlatList
    scrollEnabled=false
    horizontal
    data=emptyArray
    ListEmptyComponent=(<DraggableList />)
  />

没有更多警告,我认为这是警告推荐的模式。

【讨论】:

【参考方案8】:

正如@Brahim 上面所说,将horizontal 属性设置为true 似乎可以解决嵌入在ScrollView 中的FlatList 的问题。

【讨论】:

我不知道为什么这么多人提到horizontal属性解决方案,这完全破坏了我的设计,我相信其他人也是如此 如果使用numColumns 属性,那么horizontal 属性将完全破坏它。【参考方案9】:

我尝试了一些方法来解决这个问题,包括ListHeaderComponentListFooterComponent,但都不适合我。

我想实现的布局是这样的,我想滚进去一次。

<ScrollView>
  <View>I'm the first view</View>
  <View>I'm the second view</View>
  <MyFlatList />
</ScrollView>

首先我要感谢this issue 和 cmets,它们给了我很多想法。

我正在考虑将ListHeaderComponent 放在平面列表上方,但由于我的Flatlist 的方向是列,所以我想放置的标题位于Flatlist 的左侧:(

然后我不得不尝试VirtualizedList-backed 的东西。我只是尝试将所有组件打包在VirtualizedList 中,其中renderItems 提供索引,我可以有条件地将组件传递给renderItems

我本可以使用 Flatlist 进行此操作,但我还没有尝试过。 最后它看起来像这样。

<View>
  <Virtualizedlist
    data=[]
    initialNumToRender=1
    renderItem=(props)=>
      props.index===0 ? (1st view here) : props.index===1 ? (2nd view here) : (my flatlist)
    
    keyExtractor=item => item.key
    getItemCount=2
    getItem= (data, index) => 
      return 
        id: Math.random().toString(12).substring(0),
      
    
  />
</View>

(inside which lazyly renders↓)
  <View>I'm the first view</View>
  <View>I'm the second view</View>
  <MyFlatList />  

当然可以滚动整个屏幕。

【讨论】:

【参考方案10】:

所以我在 &lt;ScrollView&gt; 中使用基于选择器的组件时遇到了同样的问题,而帮助我解决问题的一件事是添加 keyboardShouldPersistTaps=true&lt;ScrollView&gt; 中作为道具。

这是我的代码 sn-p。

<ScrollView keyboardShouldPersistTaps=true> 
      <SelectionDD studentstatus=studentStatus/>
      <SearchableDD collegeNames=collegeNames placeholder='University'/>
</ScrollView>

【讨论】:

不推荐使用 .. 必须是 keyboardShouldPersistTaps="always" 我不确定它最近是否发生了变化。但是非常感谢您提供的信息!【参考方案11】:
<ScrollView horizontal=false style=width: '100%', height: '100%'>
   <ScrollView horizontal=true style=width: '100%', height: '100%'>
      <FlatList ... />
   </ScrollView>
</ScrollView>

【讨论】:

【参考方案12】:

在我看来,我可以使用地图而不是 FlatList。但就我而言,我不想显示大列表。不使用 FlatList 可能会导致性能问题。所以我用它来抑制警告https://github.com/GeekyAnts/NativeBase/issues/2947#issuecomment-549210509

【讨论】:

【参考方案13】:

由于在 ScrollView 中使用 FlatList,此错误消失了。你可以像下面这样写代码。

<SafeAreaView style=styles.container>
            <View style=styles.container>
              <View>
                <Header />
              </View>

                (list.length == 0) &&
                  <View style=flex:1, margin: 15>
                    <Text style=textAlign: 'center'>No peripherals</Text>
                  </View>
                
                <FlatList 
                  data=list
                  renderItem=( item ) => this.renderItem(item) 
                  keyExtractor=item => item.id
                />
            </View>
          </SafeAreaView>

【讨论】:

【参考方案14】:

在不隐藏 YellowBox 的情况下,您仍然可以在可滚动视图中实现可滚动视图。您可以使用this library。它取代了 React Native 中的默认 Scrollview。

【讨论】:

【参考方案15】:

这可能会对其他人有所帮助,请务必检查组件的嵌套方式。从顶部组件中移除 ScrollView 解决了这个问题。

我遇到了这个问题,因为我基本上有两个这样嵌套的组件:

组件 1

<ScrollView>
   <OtherStuff />

   <ListComponent />
</ScrollView>

我的第二个组件“ListComponent”有一个 FlatList 已经用 SafeAreaView 包装。

<SafeAreaView style=styles.container>
    <FlatList
        data=todoData
        renderItem=renderItem
        ItemSeparatorComponent=() => <View style=styles.separator />
        keyExtractor=item => item.id.toString()
    />
</SafeAreaView>

最后我用 View 替换了第一个组件中的 ScrollView。

【讨论】:

【参考方案16】:

事实上,据我所知,使用嵌套的 VirtualizedLists 总是会导致性能问题,只是对该问题的警告是新的。我尝试了我在互联网上找到的所有内容,但没有一个有帮助。我现在使用 ScrollView,或者当您只有一个带有 maxHeight 的普通视图时,如果内容高度大于您视图的 maxHeight,您将能够滚动。 所以:

<ScrollView>
   items.map((item, index) =>
       <YourComponent key=index item=item />
   )
</ScrollView>

或者只是:

<View style=maxHeight: MAX_HEIGHT>
    items.map((item, index) =>
       <YourComponent key=index item=item />
    )
</View>

【讨论】:

FlatList 通常用于动态加载和显示数据。在大多数情况下,将其转换为静态列表并不是一种方法。【参考方案17】:

我遇到了同样的问题,只是通过删除 FlatList 周围的 ScrollView 来解决它。因为默认情况下,FlatList 根据其呈现的内容长度提供滚动功能。 ?

【讨论】:

如果您在同一屏幕上有与 FlatList 同级的其他内容/组件,这将不起作用。

以上是关于React-Native 另一个 VirtualizedList 支持的容器的主要内容,如果未能解决你的问题,请参考以下文章

如何将 state 下的数据导出到另一个文件?(react-native)

React-Native:在另一个类中访问 TextField 值

来自另一个文件的 React-Native 反应导航

如何在 react-native 中将函数的结果从一个组件传递到另一个组件?

通过单击另一个组件中的按钮,react-native重新呈现组件

关闭键盘 React-Native