How to re-render flatlist?

ReactjsReact NativeReact Native-Flatlist

Reactjs Problem Overview


Unlike ListView we can update this.state.datasource. Is there any method or example to update FlatList or re-render it?

My goal is to update the text value when user press button ...

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

Reactjs Solutions


Solution 1 - Reactjs

Use the extraData property on your FlatList component.

As the documentation states:

> 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.

Solution 2 - Reactjs

For quick and simple solution Try:

  1. set extra data to a boolean value.

    extraData={this.state.refresh}

  2. Toggle the value of boolean state when you want to re-render/refresh list

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

Solution 3 - Reactjs

Oh that's easy, just use extraData

You see the way extra data works behind the scenes is the FlatList or the VirtualisedList just checks wether that object has changed via a normal onComponentWillReceiveProps method.

So all you have to do is make sure you give something that changes to the extraData.

Here's what I do:

I'm using immutable.js so all I do is I pass a Map (immutable object) that contains whatever I want to watch.

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

In that way, when this.props.foo or this.props.bar change, our CustomComponentRow will update, because the immutable object will be a different one than the previous.

Solution 4 - Reactjs

OK.I just found out that if we want the FlatList to know the data change outside of the data prop,we need set it to extraData, so I do it like this now:

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

refer to : https://facebook.github.io/react-native/docs/flatlist#extradata

Solution 5 - Reactjs

after lots of searching and looking for real answer finally i got the answer which i think it is the best :

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

my main problem was (KeyExtractor) i was not using it like this . not working : keyExtractor={ (item) => item.ID} after i changed to this it worked like charm i hope this helps someone.

Solution 6 - Reactjs

If you are going to have a Button, you can update the data with a setState inside the onPress. SetState will then re-render your FlatList.

Solution 7 - Reactjs

Just an extension on the previous answers here. Two parts to ensure, Make sure that you add in extraData and that your keyExtractor is unique. If your keyExtractor is constant a rerender will not be triggered.

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

Solution 8 - Reactjs

I solved this problem by adding extraData={this.state} Please check code below for more detail

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

Solution 9 - Reactjs

In this example, to force a re-render, just change the variable machine

const [selected, setSelected] = useState(machine)

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

Solution 10 - Reactjs

I have replaced FlatList with SectionList and it is updates properly on state change.

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

The only thing need to keep in mind is that section have diff structure:

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

Solution 11 - Reactjs

For me, the trick was extraData and drilling down into the item component one more time

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 });
    }
  }
}

Solution 12 - Reactjs

Put variables that will be changed by your interaction at extraData

You can be creative.

For example if you are dealing with a changing list with checkboxes on them.

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

Solution 13 - Reactjs

If we want the FlatList to know the data change both prop and state,we can construct an object referencing both prop and state and refresh the flatlist.

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

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

Solution 14 - Reactjs

In react-native-flatlist, they are a property called as extraData. add the below line to your flatlist.

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

Solution 15 - Reactjs

I am using functional component, in that I am using Flatlist with redux data. I am managing all the state with Redux store. Here is the solution to update the Flatlist data after the api call.

I was first doing like this:-

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

but the data was not re-rendering my Flatlist data at all.

As a solution I did like given Below:-

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

I am passing the Redux state directly to the Flatlist Datasource rather than allocating it to the variable.

Thank you.

Solution 16 - Reactjs

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

Solution 17 - Reactjs

For those using redux, I used extraData prop and added loading there what I also did was I created a custom hook called 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;
};

and used it like this on my Item.

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]);

So what basically happened here was, your item will check if data is from undefined (first time). Then It will check if some data property has changed and if it has, you should do something.

Solution 18 - Reactjs

Doing like below will instantly make the flatlist item change reflected instantly. You can do this similarly in component also if you are not using 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 };

Solution 19 - Reactjs

Just use:

onRefresh={true}

inside your flatList component.

Solution 20 - Reactjs

Flatlist's extraData wasn't working for me and I happened to be using a prop from redux. This sounded similar to issues from the comments in ED209's answer. I ended up manually calling setState when I receive the prop.

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

For those of you using > React 17 use getDerivedStateFromProps

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionshalonteohView Question on Stackoverflow
Solution 1 - ReactjsED209View Answer on Stackoverflow
Solution 2 - ReactjsHradesh KumarView Answer on Stackoverflow
Solution 3 - ReactjsSudoPlzView Answer on Stackoverflow
Solution 4 - ReactjsMahdi BashirpourView Answer on Stackoverflow
Solution 5 - Reactjsramin azadiView Answer on Stackoverflow
Solution 6 - ReactjsWilliamCView Answer on Stackoverflow
Solution 7 - ReactjsNicholas KuhneView Answer on Stackoverflow
Solution 8 - Reactjsnawaab saabView Answer on Stackoverflow
Solution 9 - ReactjsBill ZelenkoView Answer on Stackoverflow
Solution 10 - ReactjsjamlandView Answer on Stackoverflow
Solution 11 - ReactjsDazzleView Answer on Stackoverflow
Solution 12 - ReactjsgoodhyunView Answer on Stackoverflow
Solution 13 - ReactjsYogaraj SaravananView Answer on Stackoverflow
Solution 14 - ReactjsraviView Answer on Stackoverflow
Solution 15 - ReactjsPravin GhorleView Answer on Stackoverflow
Solution 16 - ReactjstarokinsView Answer on Stackoverflow
Solution 17 - Reactjsjohn joshua dabloView Answer on Stackoverflow
Solution 18 - ReactjsAjmal HasanView Answer on Stackoverflow
Solution 19 - ReactjsTaha khozooieView Answer on Stackoverflow
Solution 20 - ReactjsMr.LeeView Answer on Stackoverflow