Jak ponownie wyrenderować flatlistę?

86

W przeciwieństwie do ListView możemy zaktualizować this.state.datasource. Czy jest jakaś metoda lub przykład aktualizacji FlatList lub ponownego renderowania?

Moim celem jest aktualizacja wartości tekstowej, gdy użytkownik naciśnie przycisk ...

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} />
shalonteoh
źródło
7
Dokumentacja FlatList mówi „To jest a, PureComponentco oznacza, że ​​nie wyrenderuje się ponownie, jeśli właściwości pozostają płytkie - równe. Upewnij się, że wszystko, od czego renderItemzależy twoja funkcja, jest przekazywane jako właściwość, która nie jest ===po aktualizacji, w przeciwnym razie interfejs użytkownika może się nie zaktualizować po zmianach. Obejmuje to stan właściwości datai komponentu nadrzędnego ”. Czy postępujesz zgodnie z tą radą?
Jordan Running
3
Bez względu na to, z czym próbowałem extraDatai shouldItemUpdate, nie mogłem uzyskać listy do ponownego renderowania. Skończyło się na tym, że wyczyściłem stan, czekałem, aż się wyrenderuje, a następnie zaktualizowałem stan. this.setState({ data: null }, () => { this.setState({ data: actualData }) });
Joshua Pinter

Odpowiedzi:

186

Użyj extraDatawłaściwości w składniku FlatList.

Jak podaje dokumentacja:

Przechodząc extraData={this.state}do FlatList, upewniamy się, że FlatListwyrenderuje się ponownie, gdy state.selectedzmiany. Bez ustawienia tej właściwości FlatListnie wiedziałoby, że musi ponownie wyrenderować jakiekolwiek elementy, ponieważ jest również a, PureComponenta porównanie rekwizytów nie pokaże żadnych zmian.

ED209
źródło
34
Używam Redux iw takim przypadku przesyłam dane jak data={this.props.searchBookResults}i ani nie, extraData={this.state}ani extraData={this.props}dla mnie. I też data={this.props.searchBookResults}nie działa. Co robić ?
Sujit
8
Zastosowanie dodatkowymi danymi: aby odświeżyć <FlatList>... data={this.props.searchBookResults} extraData={this.state.refresh} onPress={()={this.setState({ refresh: !refresh})}
Nay
9
Zmagam się z tym samym problemem. Nie ma znaczenia, co przekazuję extraData, komponent się nie aktualizuje :(
Denis Cappelini
2
@DenisCappelini, upewnij się, że dane przekazane do właściwości extraDatazmieniają się, gdy element [elementy] potomne muszą zostać ponownie wyrenderowane. Na przykład, jeśli elementy listy mogą być aktywne / nieaktywne, upewnij się, że zmienna stanu, czy część this.stateobiektu lub this.propsobiektu jest tym, co powinna znaleźć się w środku extraData. Może to być kursor lub tablica aktywnych przedmiotów itp.
Emperor_Earth
1
@Sujit Miałem ten sam problem, ale potem zdałem sobie sprawę, że wdrożyłem shouldComponentUpdate(), po zaktualizowaniu lub całkowitym skomentowaniu, wszystko działało tak, jak opisano w dokumentacji.
JanithaR
51

Szybkie i proste rozwiązanie Wypróbuj:

  1. ustaw dodatkowe dane na wartość logiczną.

    extraData = {this.state.refresh}

  2. Przełącz wartość stanu boolowskiego, gdy chcesz ponownie wyrenderować / odświeżyć listę

    this.setState({ 
        refresh: !this.state.refresh
    })
    
Hradesh Kumar
źródło
Właśnie tego potrzebuję, ponieważ będę dodawać dane do rekwizytu danych. Poza tym jest to super dziwna implementacja zespołu React-Native ... o wiele bardziej sensowne byłoby posiadanie funkcji odświeżania lub właściwości danych. IE: this.data.refresh(). Zamiast tego ustawiamy wartość logiczną i zmieniamy ją. Wartość logiczna sama w sobie nie ma znaczenia, więc jaki jest sens w jej istnieniu? ... (Nie ma sensu, poza
poprawnym
@HradeshKumar Robię to, ale ostatnia pozycja w Danych nie może zniknąć!
DevAS
to działa jak urok, ale nadal nie wiem, dlaczego this.state.usersnie działało, mimo że zmieniałem flagę u niektórych użytkowników.
shyammakwana.me
21

Och, to proste, po prostu użyj extraData

Widzisz, w jaki sposób dodatkowe dane działają za kulisami, to FlatList lub VirtualisedList po prostu sprawdza, czy obiekt zmienił się normalną onComponentWillReceivePropsmetodą.

Więc wszystko, co musisz zrobić, to upewnić się, że podasz coś, co zmieni się w extraData.

Oto co robię:

Używam immutable.js, więc wszystko, co robię, to przekazanie mapy (niezmiennego obiektu), która zawiera wszystko, co chcę obejrzeć.

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

W ten sposób, kiedy this.props.foolub this.props.barzmienimy, nasz CustomComponentRowzaktualizuje się, ponieważ niezmienny obiekt będzie inny niż poprzedni.

SudoPlz
źródło
2
w końcu zrozumiałem extraData! dzięki za link do VirtualisedListkodu!
Tushar Koul
cześć @ SudoPiz Chcę ponownie wyrenderować Flatlist po usunięciu ostatniego elementu, mogę sprawdzić Q stackoverflow.com/questions/58780167/ ...
Oliver D
6

OK, właśnie się dowiedziałem, że jeśli chcemy, aby FlatList wiedziała o zmianie danych poza właściwością danych, musimy ustawić ją na extraData, więc robię to teraz tak:

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

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

Mahdi Bashirpour
źródło
1
Najlepsza implementacja ... Wolałem ustawić to tak samo jak właściwość danych, więc nie odświeża się, gdy cokolwiek w stanie się zmienia, ale jest to zdecydowanie NAJSZYBSZA implementacja. Dzięki!
Robert Kehoe
cześć @MahdiBashirpour Chcę ponownie wyrenderować Flatlistę po usunięciu ostatniego elementu, mogę sprawdzić to Q stackoverflow.com/questions/58780167/ ...
Oliver D
4

Jeśli zamierzasz mieć Button, możesz zaktualizować dane za pomocą setState wewnątrz onPress. SetState ponownie wyrenderuje FlatList.

WilliamC
źródło
2
w moim dotykowym podświetleniu znajduje się setState. setState działa poprawnie, ale płaska lista nie pokazuje aktualizacji wartości stanu -> this.state.value
shalonteoh
Wartości w Twojej FlastList nie są aktualizowane, ponieważ nie aktualizujesz bezpośrednio źródła danych. this.state.data jest renderowane za pomocą FlatList, ale w onPressie aktualizujesz tylko this.state.value.
WilliamC
przepraszam mój błąd, literówka w pytaniu. powinno być this.state.data [index] .value
shalonteoh
3

po wielu poszukiwaniach i szukaniu prawdziwej odpowiedzi w końcu otrzymałem odpowiedź, która moim zdaniem jest najlepsza:

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

moim głównym problemem był (KeyExtractor), nie używałem go w ten sposób. nie działa: keyExtractor = {(item) => item.ID} po zmianie na to działało jak urok. Mam nadzieję, że to komuś pomoże.

ramin azadi
źródło
czy możesz podać wartość this.state.refreshingi funkcję handleRefresh?
DevAS
1

Rozwiązałem ten problem, dodając extraData={this.state}Proszę sprawdzić kod poniżej, aby uzyskać więcej szczegółów

render() {
    return (
      <View style={styles.container}>
        <FlatList
          data={this.state.arr}
          extraData={this.state}
          renderItem={({ item }) => <Text style={styles.item}>{item}</Text>}
        />
      </View>
    );
  }
nawaab saab
źródło
1

To tylko rozszerzenie poprzednich odpowiedzi tutaj. Dwie części, aby upewnić się, że dodajesz extraData i że Twój keyExtractor jest unikalny. Jeśli twój keyExtractor jest stały, ponowne wysłanie nie zostanie uruchomione.

<FlatList
data={this.state.AllArray}
extraData={this.state.refresh}
renderItem={({ item,index })=>this.renderPhoto(item,index)}
keyExtractor={item => item.id}
>
                                    </FlatList>
Nicholas Kuhne
źródło
0

Wymieniłem FlatListze SectionListi to jest właściwie aktualizacje na zmiany stanu.

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

Jedyną rzeczą, o której należy pamiętać, jest to, że sectionmają strukturę diff:

const section = [{
  id: 0,
  data: this.state.data,
}]
Jamland
źródło
0

Dla mnie sztuczka polegała na tym, że extraData i jeszcze raz drążenie w komponencie przedmiotu

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 });
    }
  }
}
Oślepiać
źródło
0

Zmienne, które zostaną zmienione w wyniku interakcji, należy umieścić pod adresem extraData

Możesz być kreatywny.

Na przykład, jeśli masz do czynienia ze zmieniającą się listą z polami wyboru.

<FlatList
      data={this.state.data.items}
      extraData={this.state.data.items.length * (this.state.data.done.length + 1) }
      renderItem={({item}) => <View>  
goodhyun
źródło
0

Jeśli chcemy, aby FlatList wiedział, że dane zmieniają się zarówno we właściwości , jak i w stanie , możemy skonstruować obiekt odwołujący się do właściwości i stanu i odświeżyć płaską listę.

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

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

Yogaraj Saravanan
źródło
0

W React-native-flatlist są one właściwością o nazwie extraData. dodaj poniższą linię do swojej listy.

 <FlatList
          data={data }
          style={FlatListstyles}
          extraData={this.state}
          renderItem={this._renderItem}
       />
ravi
źródło
0

W tym przykładzie, aby wymusić ponowne renderowanie, wystarczy zmienić zmienną machine

const [selected, setSelected] = useState(machine)

useEffect(() => {
    setSelected(machine)
}, [machine])
Bill Zelenko
źródło
-1

Po prostu użyj:

onRefresh={true}

wewnątrz twojego flatListkomponentu.

Taha khozooie
źródło
1
tworzy to błąd, musisz wtedy użyć refreshingprop
mahmoudafer
-1

ExtraData Flatlist nie działało dla mnie i zdarzyło mi się używać rekwizytu z Redux. Brzmiało to podobnie do kwestii z komentarzy w odpowiedzi ED209. Skończyło się na ręcznym wywołaniu setState, gdy otrzymałem 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}
/>

Dla tych z Was, którzy używają> React 17, użyj getDerivedStateFromProps

Panie Lee
źródło