如何重新渲染平面列表?

How to re-render flatlist?

与 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} />

如果您要有一个按钮,您可以使用 onPress 中的 setState 更新数据。然后 SetState 将重新呈现您的 FlatList。

在 FlatList 组件上使用 extraData 属性。

如文档所述:

By passing extraData={this.state} to FlatList we make sure FlatList will re-render itself when the state.selected changes. Without setting this prop, FlatList would not know it needs to re-render any items because it is also a PureComponent and the prop comparison will not show any changes.

哦,很简单,用extraData

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

所以你所要做的就是确保你提供的东西会改变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 也会更新,因为不可变对象将与之前的对象不同。

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

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

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

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

要获得快速简单的解决方案,请尝试:

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

    extraData={this.state.refresh}

  2. 想要re-render/refresh列表时切换布尔状态的值

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

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

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

你可以发挥创意。

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

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

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

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

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

我通过添加 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>
    );
  }

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

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

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

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

       <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} 在我改成这个之后它就像魅力一样工作 我希望这对某人有所帮助。

只需使用:

onRefresh={true}

在您的 flatList 组件中。

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

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

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

const [selected, setSelected] = useState(machine)

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

Flatlist 的 extraData 对我不起作用,我碰巧使用了 redux 的 prop。这听起来与 ED209 的回答中的评论中的问题类似。当我收到道具时,我最终手动调用了 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

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

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

我正在使用功能组件,因为我正在使用 Flatlist 和 redux 数据。 我正在使用 Redux store 管理所有状态。 这是在 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 数据源,而不是将其分配给变量。

谢谢。

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 }
/>

对于那些使用 redux 的人,我使用了 extraData prop 并在那里添加了加载我也做了我创建了一个名为 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(第一次)。然后它将检查某些数据 属性 是否已更改,如果已更改,您应该做一些事情。

像下面那样做将立即使 flatlist 项目更改立即反映出来。如果您不使用 redux,您也可以在组件中执行类似的操作。

  let list = Object.assign([], state.auctionList);
  let objIndex;
  //Find index of specific object using findIndex method.
  objIndex = list.findIndex(
    obj => obj.auction_vehicles.vehicle_id == payload.vehicle_id,
  );

  // //Update object's property.
  list[objIndex].auction_vehicles.time_left = payload.offer_expiry_time;
  list[objIndex].auction_vehicles.starting_price = payload.amount;
  list[objIndex].auction_vehicles.bidding_status =
    payload.highest_bidder_flag;

  return { ...state, auctionList: list };