【问题标题】:How to re-render flatlist?如何重新渲染平面列表?
【发布时间】:2017-09-09 21:40:03
【问题描述】:

与 ListView 不同,我们可以更新 this.state.datasource。有什么方法或者例子可以更新 FlatList 或者重新渲染吗?

我的目标是在用户按下按钮时更新文本值...

renderEntries({ item, index }) {
    return(
        <TouchableHighlight onPress={()=> this.setState({value: this.state.data[index].value+1})>
             <Text>{this.state.data[index].value}</Text>
        </TouchableHighlight>
    )
}

<FlatList 
    ref={(ref) => { this.list = ref; }} 
    keyExtractor={(item) => item.entry.entryId} 
    data={this.state.data} 
    renderItem={this.renderEntries.bind(this)} 
    horizontal={false} />

【问题讨论】:

  • docs for FlatList 说“这是一个PureComponent,这意味着如果道具保持浅相等,它将不会重新渲染。确保您的renderItem 函数所依赖的所有内容都传递为更新后不是 === 的道具,否则您的 UI 可能不会在更改时更新。这包括 data 道具和父组件状态。您是否遵循此建议?
  • 无论我用extraDatashouldItemUpdate 尝试什么,我都无法让列表重新渲染。我最终做的是清除状态,等待渲染然后更新状态。 this.setState({ data: null }, () =&gt; { this.setState({ data: actualData }) });

标签: reactjs react-native react-native-flatlist


【解决方案1】:

在您的 FlatList 组件上使用 extraData 属性。

如文档所述:

通过将extraData={this.state} 传递给FlatList,我们确保FlatList 将在state.selected 更改时重新呈现自己。如果不设置此道具,FlatList 将不知道需要重新渲染任何项目,因为它也是 PureComponent,并且道具比较不会显示任何更改。

【讨论】:

  • 我正在使用 redux,在这种情况下发送像 data={this.props.searchBookResults} 这样的数据,extraData={this.state}extraData={this.props} 都不适合我。而data={this.props.searchBookResults} 也不起作用。怎么办?
  • 使用 extraData: 刷新你的 ... data={this.props.searchBookResults} extraData={this.state.refresh} onPress={()={this.setState({ refresh: !refresh})}
  • 我正在努力解决同样的问题。不管我传递什么extraData,组件不会更新:(
  • @DenisCappelini,确保当子项[s] 必须重新渲染时,传递到 extraData 属性的数据会发生变化。例如,如果列表项可以是活动/非活动的,请确保状态变量,无论是this.state 对象还是this.props 对象的一部分,都应该进入extraData。它可能是一个光标,也可能是一个活动项目数组等。
  • @Sujit 我遇到了同样的问题,但后来我意识到我已经实现了shouldComponentUpdate(),一旦我更新或完全注释掉,事情就像文档中描述的那样工作。
【解决方案2】:

如需快速简单的解决方案,请尝试:

  1. 将额外数据设置为布尔值。

    extraData={this.state.refresh}

  2. 当你想重新渲染/刷新列表时切换布尔状态的值

    this.setState({ 
        refresh: !this.state.refresh
    })
    

【讨论】:

  • 这正是我所需要的,因为我将向 data 道具添加数据。此外,这是 React-Native 团队的一个超级怪异的实现……在数据上拥有刷新功能或属性会更有意义。即:this.data.refresh()。相反,我们设置一个布尔值并更改它。布尔值本身没有意义,那么它存在的意义何在?...(没有意义,除了让数据刷新对吗?)
  • @HradeshKumar 我这样做了,但 Data 中的最后一项不能消失!
  • 这就像魅力一样,但我仍然不知道为什么this.state.users 不起作用,即使我正在更改某些用户的标志。
  • 对我不起作用,你能帮忙吗:stackoverflow.com/questions/65547030/…
  • 你好,希望你很好,你能帮我解决这个问题吗? stackoverflow.com/questions/65769926/…
【解决方案3】:

哦,这很简单,只需使用extraData

您会看到额外数据在幕后工作的方式是 FlatListVirtualisedList 只是通过普通的 onComponentWillReceiveProps 方法检查 wether that object has changed

所以你所要做的就是确保你给extraData提供一些改变。

这是我的工作:

我正在使用immutable.js,所以我所做的只是传递一个包含我想观看的任何内容的 Map(不可变对象)。

<FlatList
    data={this.state.calendarMonths}
    extraData={Map({
        foo: this.props.foo,
        bar: this.props.bar
    })}
    renderItem={({ item })=>((
        <CustomComponentRow
            item={item}
            foo={this.props.foo}
            bar={this.props.bar}
        />
    ))}
/>

这样,当this.props.foothis.props.bar 发生变化时,我们的CustomComponentRow 将更新,因为不可变对象将与之前的对象不同。

【讨论】:

  • 我终于明白extraData了!感谢VirtualisedList 代码的链接!
  • 你好,@SudoPiz 我想在删除最后一项后重新渲染Flatlist,可以查看这个Q stackoverflow.com/questions/58780167/…
【解决方案4】:

好的。我刚刚发现如果我们想让 FlatList 知道 data 属性之外的数据变化,我们需要将它设置为 extraData,所以我现在这样做:

<FlatList data={...} extraData={this.state} .../>

参考:https://facebook.github.io/react-native/docs/flatlist#extradata

【讨论】:

【解决方案5】:

如果您要拥有一个 Button,您可以在 onPress 中使用 setState 更新数据。然后 SetState 将重新渲染您的 FlatList。

【讨论】:

  • 我的 touchablehighlight 中有一个 setState。 setState 工作正常,但平面列表未显示状态值的更新 -> this.state.value
  • 您的 FlastList 中的值没有更新,因为您没有直接更新数据源。 this.state.data 是使用 FlatList 呈现的内容,但在 onPress 中您只更新 this.state.value。
  • 对不起,我的错误,问题错字。应该是 this.state.data[index].value
【解决方案6】:

经过大量搜索和寻找真正的答案,我终于得到了我认为最好的答案:

       <FlatList
      data={this.state.data}
      renderItem={this.renderItem}
      ListHeaderComponent={this.renderHeader}
      ListFooterComponent={this.renderFooter}
      ItemSeparatorComponent={this.renderSeparator}
      refreshing={this.state.refreshing}
      onRefresh={this.handleRefresh}
      onEndReached={this.handleLoadMore}
      onEndReachedThreshold={1}
      extraData={this.state.data}
      removeClippedSubviews={true}
      **keyExtractor={ (item, index) => index }**
              />
    .....

我的主要问题是(KeyExtractor) 我没有像这样使用它。 不工作:keyExtractor={ (item) => item.ID} 在我改成这个之后,它就像魅力一样 我希望这对某人有帮助。

【讨论】:

  • 你能把this.state.refreshing和函数handleRefresh的值放在一起吗?
【解决方案7】:

这里只是对先前答案的扩展。 要确保的两个部分,请确保您添加了 extraData 并且您的 keyExtractor 是唯一的。如果您的 keyExtractor 是常量,则不会触发重新渲染。

<FlatList
data={this.state.AllArray}
extraData={this.state.refresh}
renderItem={({ item,index })=>this.renderPhoto(item,index)}
keyExtractor={item => item.id}
>
                                    </FlatList>

【讨论】:

    【解决方案8】:

    我通过添加extraData={this.state} 解决了这个问题,请查看下面的代码了解更多详情

    render() {
        return (
          <View style={styles.container}>
            <FlatList
              data={this.state.arr}
              extraData={this.state}
              renderItem={({ item }) => <Text style={styles.item}>{item}</Text>}
            />
          </View>
        );
      }
    

    【讨论】:

      【解决方案9】:

      在本例中,要强制重新渲染,只需更改变量machine

      const [selected, setSelected] = useState(machine)
      
      useEffect(() => {
          setSelected(machine)
      }, [machine])
      

      【讨论】:

        【解决方案10】:

        我已将FlatList 替换为SectionList,它会在状态更改时正确更新。

        <SectionList
          keyExtractor={(item) => item.entry.entryId} 
          sections={section}
          renderItem={this.renderEntries.bind(this)}
          renderSectionHeader={() => null}
        />
        

        唯一需要记住的是section 有差异结构:

        const section = [{
          id: 0,
          data: this.state.data,
        }]
        

        【讨论】:

        【解决方案11】:

        对我来说,诀窍是 extraData 并再次深入到 item 组件中

        state = {
          uniqueValue: 0
        }
        
        <FlatList
          keyExtractor={(item, index) => item + index}
          data={this.props.photos}
          renderItem={this.renderItem}
          ItemSeparatorComponent={this.renderSeparator}
        />
        
        renderItem = (item) => {
          if(item.item.selected) {
            return ( <Button onPress={this.itemPressed.bind(this, item)}>Selected</Button> );
          }
          return ( <Button onPress={this.itemPressed.bind(this, item)}>Not selected</Button>);
        }
        
        itemPressed (item) {
          this.props.photos.map((img, i) => {
            if(i === item.index) {
              if(img['selected') {
                delete img.selected;
              } else {
                img['selected'] = true;
              }
              this.setState({ uniqueValue: this.state.uniqueValue +1 });
            }
          }
        }
        

        【讨论】:

        • extraData 在哪里?
        【解决方案12】:

        将您的交互更改的变量放在extraData

        你可以有创意。

        例如,如果您正在处理带有复选框的更改列表。

        <FlatList
              data={this.state.data.items}
              extraData={this.state.data.items.length * (this.state.data.done.length + 1) }
              renderItem={({item}) => <View>  
        

        【讨论】:

          【解决方案13】:

          如果我们想让 FlatList知道数据变化prop 和 state,我们可以构造一个引用 prop 和 state 的对象并刷新 flatlist。

          const hasPropOrStateChange = { propKeyToWatch: this.props, ...this.state};
          <FlatList data={...} extraData={this.hasPropOrStateChange} .../>
          

          文档:https://facebook.github.io/react-native/docs/flatlist#extradata

          【讨论】:

            【解决方案14】:

            在 react-native-flatlist 中,它们是一个称为 extraData 的属性。将以下行添加到您的平面列表中。

             <FlatList
                      data={data }
                      style={FlatListstyles}
                      extraData={this.state}
                      renderItem={this._renderItem}
                   />
            

            【讨论】:

              【解决方案15】:

              我正在使用功能组件,因为我正在使用带有 redux 数据的 Flatlist。 我正在使用 Redux 商店管理所有状态。 以下是api调用后更新Flatlist数据的解决方案。

              我一开始是这样的:-

              const DATA  = useSelector((state) => state.address.address);
              
              
              <FlatList
                  style = {styles.myAddressList}
                  data = {DATA}
                  renderItem = {renderItem}
                  keyExtractor = {item => item._id}
                  ListEmptyComponent = {EmptyList}
                  ItemSeparatorComponent={SeparatorWhite}
                  extraData = {refresh}
                  
                  />
              

              但数据根本没有重新渲染我的 Flatlist 数据。

              作为我喜欢的解决方案如下:-

              <FlatList
                  style = {styles.myAddressList}
                  data = {useSelector((state) => state.address.address)}
                  renderItem = {renderItem}
                  keyExtractor = {item => item._id}
                  ListEmptyComponent = {EmptyList}
                  ItemSeparatorComponent={SeparatorWhite}
                  />
              

              我将 Redux 状态直接传递给 Flatlist 数据源,而不是将其分配给变量。

              谢谢。

              【讨论】:

                【解决方案16】:
                const [itemSelected, setItemSelected] = setState(null);
                ....
                const FlatListItem = (item) => {
                    return (
                        <TouchableOpacity onPress={() => setItemSelected(item.id)}>
                            <View style={ (itemSelected === item.id) ? style.itemWrapperActive : style.itemWrapper }>
                                <Text>{ item.label }</Text>
                            </View>
                        </TouchableOpacity>
                    )
                }
                ....
                <FlatList
                    ItemSeparatorComponent={() => <View style={{ width: 20 }} />}
                    data={ flatListData }
                    renderItem={ ({item}) => FlatListItem(item) }
                    keyExtractor={ (item) => item.id }
                    extraData={ itemSelected }
                />
                

                【讨论】:

                  【解决方案17】:

                  对于那些使用 redux 的人,我使用了 extraData 属性并在那里添加了加载,我还创建了一个名为 usePrevious 的自定义钩子

                  import {useEffect, useRef} from 'react';
                  
                  export const usePrevious = <T>(value: T): T | undefined => {
                    const ref = useRef<T>();
                    useEffect(() => {
                      ref.current = value;
                    });
                    return ref.current;
                  };
                  

                  并像这样在我的项目上使用它。

                  const prevData = usePrevious({data});
                  
                  //CODES...
                  
                  useEffect(() => {
                      if (prevData?.data === undefined) {
                        return;
                      }
                      if (prevData?.data?.someID !== data?.someId) {
                        // do something.
                        showSubChildren(false)
                      }
                    }, [data?.AuctionName, prevData, resetItemStates]);
                  

                  所以这里基本上发生的是,您的项目将检查数据是否来自undefined(第一次)。然后它会检查某些数据属性是否发生了变化,如果有,你应该做点什么。

                  【讨论】:

                    【解决方案18】:

                    只需使用:

                    onRefresh={true}
                    

                    在您的 flatList 组件中。

                    【讨论】:

                    • 这会产生错误,然后你需要使用refreshingprop
                    【解决方案19】:

                    Flatlist 的 extraData 对我不起作用,我碰巧使用了来自 redux 的道具。这听起来类似于 ED209 答案中来自 cmets 的问题。当我收到道具时,我最终手动调用了 setState。

                    componentWillReceiveProps(nextProps: StateProps) {
                        if (this.props.yourProp != null && nextProps.yourProp) {
                            this.setState({ yourState: processProp(nextProps.yourProp) });
                        }
                    }
                    
                    
                    <FlatList
                      data={this.state.yourState}
                      extraData={this.state.yourState}
                    />
                    

                    对于那些使用 > React 17 的人,请使用 getDerivedStateFromProps

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 2020-01-04
                      • 2021-03-10
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      相关资源
                      最近更新 更多