Como renderizar novamente a lista plana?

86

Ao contrário de ListView, podemos atualizar this.state.datasource. Existe algum método ou exemplo para atualizar FlatList ou renderizá-lo novamente?

Meu objetivo é atualizar o valor do texto quando o usuário pressiona o botão ...

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
fonte
7
Os documentos para FlatList dizem "Este é um, o PureComponentque significa que não será renderizado novamente se os adereços permanecerem rasos. Certifique-se de que tudo de que sua renderItemfunção depende seja passado como um acessório que não está ===após atualizações, caso contrário, sua IU pode não ser atualizada nas alterações. Isso inclui o dataestado do componente principal e prop. " Você está seguindo este conselho?
Jordan Running em
3
Não importa o que eu tentei extraDatae shouldItemUpdatenão consegui fazer a lista para renderizar novamente. O que acabei fazendo foi limpar o estado, aguardar que isso fosse renderizado e depois atualizar o estado. this.setState({ data: null }, () => { this.setState({ data: actualData }) });
Joshua Pinter

Respostas:

186

Use a extraDatapropriedade em seu componente FlatList.

Conforme afirma a documentação:

Ao passar extraData={this.state}para FlatList, garantimos que FlatListserá renderizado novamente quando as state.selectedalterações. Sem definir esta prop, FlatListnão saberia que precisa renderizar novamente qualquer item porque também é um PureComponente a comparação de prop não mostrará nenhuma mudança.

ED209
fonte
34
Estou usando redux e nesse caso o envio de dados like data={this.props.searchBookResults}e nem extraData={this.state}nem extraData={this.props}está funcionando para mim. E data={this.props.searchBookResults}não está funcionando também. O que fazer ?
Sujit
8
Use extraData: para atualizar sua <FlatList>... data={this.props.searchBookResults} extraData={this.state.refresh} onPress={()={this.setState({ refresh: !refresh})}
Não
9
Estou lutando com o mesmo problema. Não importa o que eu passe extraData, o componente não atualiza :(
Denis Cappelini
2
@DenisCappelini, certifique-se de que os dados passados ​​para o extraDataprop sejam alterados quando os itens filhos precisarem ser renderizados novamente. Por exemplo, se os itens da lista podem estar ativos / inativos, certifique-se de que a variável de status, seja parte do this.stateobjeto ou this.propsobjeto, é o que deve entrar extraData. Pode ser um cursor ou uma matriz de itens ativos, etc.
Emperor_Earth
1
@Sujit Eu estava tendo o mesmo problema, mas então percebi que havia implementado shouldComponentUpdate(), assim que atualizei ou comentei completamente, as coisas estavam funcionando exatamente como descrito na documentação.
JanithaR
51

Para uma solução rápida e simples, experimente:

  1. defina dados extras para um valor booleano.

    extraData = {this.state.refresh}

  2. Alterne o valor do estado booleano quando você quiser renderizar novamente / atualizar a lista

    this.setState({ 
        refresh: !this.state.refresh
    })
    
Hradesh Kumar
fonte
É exatamente disso que preciso, já que adicionarei dados à propriedade de dados. Além disso, essa é uma implementação super estranha pela equipe React-Native ... faria muito mais sentido ter uma função de atualização ou propriedade nos dados. IE: this.data.refresh(). Em vez disso, definimos um booleano e o alteramos. O valor booleano em si não tem significado, então qual é o objetivo dele existir? ... (Não há nenhum ponto, além de fazer a atualização de dados correta?)
YungGun 01 de
@HradeshKumar Eu faço isso, mas o último item dentro do Data ele não pode desaparecer!
DevAS
isso funciona muito bem, mas ainda não sei por que this.state.usersnão estava funcionando, embora eu tenha mudado um sinalizador em alguns usuários.
shyammakwana.me
21

Oh, isso é fácil, basta usar extraData

Você vê a maneira como os dados extras funcionam nos bastidores: a FlatList ou a VirtualisedList apenas verifica se o objeto foi alterado por meio de um onComponentWillReceivePropsmétodo normal .

Portanto, tudo o que você precisa fazer é certificar-se de fornecer algo que mude ao extraData.

Aqui está o que eu faço:

Estou usando o immutable.js, então tudo que faço é passar um Mapa (objeto imutável) que contém tudo o que desejo assistir.

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

Dessa forma, quando this.props.fooou this.props.barmudar, nosso CustomComponentRowserá atualizado, pois o objeto imutável será um diferente do anterior.

SudoPlz
fonte
2
eu finalmente entendi extraData! obrigado pelo link para o VirtualisedListcódigo!
Tushar Koul,
Olá, @ SudoPiz, quero renderizar novamente a lista plana após excluir o último item, pode verificar este Q stackoverflow.com/questions/58780167/…
Oliver D
6

OK. Acabei de descobrir que, se quisermos que a FlatList conheça a alteração dos dados fora da propriedade de dados, precisamos defini-la como extraData, então faço assim agora:

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

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

Mahdi Bashirpour
fonte
1
A melhor implementação ... Eu preferi defini-lo como o mesmo que a propriedade de dados, então ele não atualiza quando algo no estado muda, mas esta é a implementação FÁCIL de longe. Obrigado!
Robert Kehoe
Olá, @MahdiBashirpour, quero renderizar novamente a lista plana após excluir o último item, pode verificar este Q stackoverflow.com/questions/58780167/…
Oliver D
4

Se você vai ter um botão, pode atualizar os dados com um setState dentro do onPress. SetState irá então renderizar novamente sua FlatList.

WilliamC
fonte
2
há um setState em meu realce tocável. o setState está funcionando bem, mas a lista plana não mostra a atualização do valor do estado -> this.state.value
shalonteoh
Os valores em seu FlastList não estão atualizando porque você não está atualizando a fonte de dados diretamente. this.state.data é o que é renderizado com a FlatList, mas no onPress você está apenas atualizando this.state.value.
WilliamC de
desculpe meu erro, pergunta de erro de digitação. deve ser this.state.data [index] .value
shalonteoh
3

Depois de muito pesquisar e procurar por uma resposta real, finalmente consegui a resposta que acho que é a melhor:

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

meu principal problema era (KeyExtractor) eu não o estava usando assim. não funciona: keyExtractor = {(item) => item.ID} depois que mudei para isso, funcionou perfeitamente, espero que ajude alguém.

Ramin Azadi
fonte
você pode colocar o valor de this.state.refreshinge função handleRefresh?
DevAS de
1

Resolvi este problema adicionando extraData={this.state}Verifique o código abaixo para obter mais detalhes

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
fonte
1

Apenas uma extensão das respostas anteriores aqui. Duas partes para garantir, certifique-se de adicionar extraData e que seu keyExtractor é exclusivo. Se seu keyExtractor for constante, um re-renderizador não será acionado.

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

Eu substituí FlatListpor SectionListe é atualizado corretamente na mudança de estado.

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

A única coisa que você precisa ter em mente é que sectiontem uma estrutura diferente:

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

Para mim, o truque era extraData e aprofundar no componente do item mais uma vez

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 });
    }
  }
}
Deslumbrar
fonte
0

Coloque variáveis ​​que serão alteradas por sua interação em extraData

Você pode ser criativo.

Por exemplo, se você estiver lidando com uma lista de alteração com caixas de seleção.

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

Se quisermos que a FlatList saiba que os dados mudam tanto prop quanto estado , podemos construir um objeto referenciando ambos prop e state e atualizar a flatlist.

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

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

Yogaraj Saravanan
fonte
0

Em react-native-flatlist, eles são uma propriedade chamada extraData. adicione a linha abaixo à sua lista plana.

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

Neste exemplo, para forçar uma nova renderização, basta alterar a variável machine

const [selected, setSelected] = useState(machine)

useEffect(() => {
    setSelected(machine)
}, [machine])
Bill Zelenko
fonte
-1

Apenas use:

onRefresh={true}

dentro do seu flatListcomponente.

Taha khozooie
fonte
1
isso cria um erro, você precisa usar refreshingprop
mahmoudafer
-1

O extraData do Flatlist não estava funcionando para mim e por acaso eu estava usando um prop do redux. Isso soou semelhante aos problemas dos comentários na resposta do ED209. Acabei chamando setState manualmente quando recebo a proposta.

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

Para aqueles que usam> React 17, use getDerivedStateFromProps

Senhor Lee
fonte