如何重新渲染平面列表?

Posted

技术标签:

【中文标题】如何重新渲染平面列表?【英文标题】: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 ) ); 【参考方案1】:

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

如文档所述:

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

【讨论】:

我正在使用 redux,在这种情况下发送像 data=this.props.searchBookResults 这样的数据,extraData=this.stateextraData=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】:

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

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

    extraData=this.state.refresh

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

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

【讨论】:

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

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

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

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

【讨论】:

最好的实现......我更喜欢将它设置为与 data 属性相同,因此当状态发生任何变化时它不会刷新,但这是迄今为止最简单的实现。谢谢! 你好,@MahdiBashirpour 我想在删除最后一项后重新渲染 Flatlist,可以查看这个 Q ***.com/questions/58780167/… 你好,希望你很好,你能帮我解决这个问题吗? ***.com/questions/65769926/… 嗨,马赫迪,你能看看这个问题吗? ***.com/questions/65786115/…【参考方案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,
]

【讨论】:

你好,希望你很好,你能帮我解决这个问题吗? ***.com/questions/65769926/…【参考方案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

【讨论】:

以上是关于如何重新渲染平面列表?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Redux 添加更多数据时,带有分页结果的平面列表会导致重新渲染

如何实现 Activity 指示器进行渲染,直到显示平面列表数据?反应原生

在平面列表中渲染许多图像时,如何将包含图像位置的道具传递给图像源?

反应平面列表渲染项

将项目添加到列表后如何避免重新渲染?

当下拉列表的值发生变化时,如何重新渲染 Flatlist?