Come rieseguire il rendering di flatlist?


88

A differenza di ListView, possiamo aggiornare this.state.datasource. Esiste un metodo o un esempio per aggiornare FlatList o riprodurlo nuovamente?

Il mio obiettivo è aggiornare il valore del testo quando l'utente preme il pulsante ...

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

8
I documenti per FlatList dicono "Questo è un PureComponentche significa che non verrà eseguito nuovamente il rendering se gli oggetti di scena rimangono poco profondi. Assicurati che tutto ciò da cui renderItemdipende la tua funzione sia passato come un oggetto che non è ===dopo gli aggiornamenti, altrimenti la tua interfaccia utente potrebbe non aggiornarsi sulle modifiche. Ciò include il dataprop e lo stato del componente padre. " Stai seguendo questo consiglio?
Jordan in esecuzione il

3
Indipendentemente da ciò che ho provato extraDatae shouldItemUpdate, non sono riuscito a riprodurre nuovamente l'elenco. Quello che ho finito per fare è stato ripulire lo stato, aspettare che venisse visualizzato e quindi aggiornare lo stato. this.setState({ data: null }, () => { this.setState({ data: actualData }) });
Joshua Pinter

Risposte:


193

Utilizza la extraDataproprietà sul tuo componente FlatList.

Come afferma la documentazione:

Passando extraData={this.state}a FlatListci assicuriamo che FlatListeseguirà nuovamente il rendering quando verranno state.selectedapportate modifiche. Senza impostare questo prop, FlatListnon saprei che ha bisogno di rieseguire il rendering di alcun elemento perché è anche un PureComponente il confronto dell'elica non mostrerà alcuna modifica.


36
Sto usando redux e in tal caso l'invio di dati come data={this.props.searchBookResults}e né extraData={this.state}extraData={this.props}funziona per me. E data={this.props.searchBookResults}non funziona neanche. Cosa fare ?
Sujit

11
Usa extraData: per aggiornare il tuo <FlatList>... data={this.props.searchBookResults} extraData={this.state.refresh} onPress={()={this.setState({ refresh: !refresh})}
Nay

9
Sto lottando con lo stesso problema. Non importa cosa trasmetto extraData, il componente non si aggiorna :(
Denis Cappelini

2
@DenisCappelini, assicurati che i dati passati nell'elica cambino extraDataquando gli elementi figlio devono essere rieseguiti. Ad esempio, se gli elementi dell'elenco possono essere attivi / inattivi, assicurati che la variabile di stato, indipendentemente dal fatto che parte this.statedell'oggetto o this.propsdell'oggetto sia ciò che dovrebbe essere contenuto extraData. Potrebbe essere un cursore o un array di elementi attivi, ecc.
Emperor_Earth

1
@ Sujit stavo riscontrando lo stesso problema ma poi mi sono reso conto di aver implementato il shouldComponentUpdate(), una volta aggiornato o commentato completamente, le cose funzionavano proprio come descritto nella documentazione.
JanithaR

54

Per una soluzione rapida e semplice Prova:

  1. imposta dati aggiuntivi su un valore booleano.

    extraData = {this.state.refresh}

  2. Alterna il valore dello stato booleano quando si desidera rieseguire il rendering / aggiornare l'elenco

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

Questo è esattamente ciò di cui ho bisogno poiché aggiungerò dati al supporto dati. Inoltre, questa è un'implementazione super strana del team React-Native ... avrebbe molto più senso avere una funzione o una proprietà di aggiornamento sui dati. IE: this.data.refresh(). Invece, impostiamo un valore booleano e lo modifichiamo. Il valore booleano in sé non ha significato, quindi qual è il punto in esso esistente? ... (Non ha senso, a parte l'aggiornamento dei dati giusto?)
YungGun

@HradeshKumar Lo faccio ma l'ultimo elemento all'interno di Data non può scomparire!
DevAS

funziona come un fascino, ma ancora non so perché this.state.usersnon funzionasse, anche se stavo cambiando una bandiera in alcuni utenti.
shyammakwana.me

Non funziona per me, potete per favore aiuto: stackoverflow.com/questions/65547030/...
Gayatri Dipali

21

Oh è facile, basta usare extraData

Vedi il modo in cui i dati extra funzionano dietro le quinte è il FlatList o il VirtualisedList controlla solo se quell'oggetto è cambiato tramite un onComponentWillReceivePropsmetodo normale .

Quindi tutto ciò che devi fare è assicurarti di dare qualcosa che cambi al file extraData.

Ecco cosa faccio:

Sto usando immutable.js quindi tutto quello che faccio è passare una mappa (oggetto immutabile) che contiene tutto ciò che voglio guardare.

<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 questo modo, quando this.props.fooo this.props.barcambia, il nostro CustomComponentRowsi aggiornerà, perché l'oggetto immutabile sarà diverso dal precedente.


2
finalmente ho capito extraData! grazie per il link al VirtualisedListcodice!
Tushar Koul

ciao, @ SudoPiz Voglio rieseguire il rendering di Flatlist dopo aver eliminato l'ultimo elemento, posso controllare questo Q stackoverflow.com/questions/58780167/…
Oliver D

6

OK, ho appena scoperto che se vogliamo che FlatList conosca la modifica dei dati al di fuori del prop data, dobbiamo impostarlo su extraData, quindi ora lo faccio in questo modo:

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

fare riferimento a: https://facebook.github.io/react-native/docs/flatlist#extradata


2
La migliore implementazione ... Ho preferito impostarlo come il supporto dati, quindi non si aggiorna quando qualcosa nello stato cambia, ma questa è di gran lunga l'implementazione PIÙ FACILE. Grazie!
Robert Kehoe,

ciao, @MahdiBashirpour Voglio rieseguire il rendering di Flatlist dopo aver eliminato l'ultimo elemento, posso controllare questo Q stackoverflow.com/questions/58780167/…
Oliver D

4

Se hai intenzione di avere un Button, puoi aggiornare i dati con un setState all'interno di onPress. SetState eseguirà quindi nuovamente il rendering della tua FlatList.


3
c'è un setState nella mia evidenziazione tangibile. setState funziona correttamente ma la flatlist non mostra l'aggiornamento del valore dello stato -> this.state.value
shalonteoh

I valori nel tuo FlastList non si aggiornano perché non stai aggiornando direttamente l'origine dati. this.state.data è ciò che viene visualizzato con FlatList, ma in onPress stai aggiornando solo this.state.value.
WilliamC

scusa il mio errore, errore di battitura della domanda. dovrebbe essere this.state.data [index] .value
shalonteoh

4

dopo molte ricerche e cercando una risposta reale finalmente ho ottenuto la risposta che penso sia la migliore:

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

il mio problema principale era (KeyExtractor) non lo stavo usando in questo modo. non funziona: keyExtractor = {(item) => item.ID} dopo che sono passato a questo ha funzionato come un fascino spero che questo aiuti qualcuno.


puoi mettere il valore di this.state.refreshinge funzione handleRefresh?
DevAS

2

Solo un'estensione delle risposte precedenti qui. Due parti per assicurarti, assicurati di aggiungere extraData e che il tuo keyExtractor sia unico. Se il tuo keyExtractor è costante, il rendering non verrà attivato.

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

1

Ho risolto questo problema aggiungendo extraData={this.state}Si prega di controllare il codice di seguito per maggiori dettagli

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

0

L'ho sostituito FlatListcon SectionListe si aggiorna correttamente al cambio di stato.

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

L'unica cosa da tenere a mente è che sectionhanno una struttura diff:

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

0

Per me, il trucco era extraData e il drill-down nel componente item ancora una volta

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

0

Metti le variabili che verranno modificate dalla tua interazione in extraData

Puoi essere creativo.

Ad esempio, se hai a che fare con un elenco di modifiche con caselle di controllo.

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


0

In react-native-flatlist, sono una proprietà chiamata extraData. aggiungi la riga sotto alla tua lista piatta.

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

0

In questo esempio, per forzare un nuovo rendering, è sufficiente modificare la variabile machine

const [selected, setSelected] = useState(machine)

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

-1

Usa solo:

onRefresh={true}

all'interno del tuo flatListcomponente.


1
questo crea un errore, quindi refreshingdevi usare prop
mahmoudafer

-1

ExtraData di Flatlist non funzionava per me e mi è capitato di utilizzare un prop da redux. Sembrava simile ai problemi dei commenti nella risposta di ED209. Ho finito per chiamare manualmente setState quando ricevo il 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}
/>

Per quelli di voi che usano> React 17 usate getDerivedStateFromProps

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.