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

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.


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

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


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


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.


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.


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

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>

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,
}]

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

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>  


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

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


-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

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.