Как повторно отрендерить плоский список?


86

В отличие от ListView, мы можем обновить this.state.datasource. Есть ли какой-либо метод или пример для обновления FlatList или повторного рендеринга?

Моя цель - обновить текстовое значение, когда пользователь нажимает кнопку ...

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
В документации для FlatList говорится: «Это PureComponentозначает, что он не будет повторно визуализироваться, если реквизиты остаются мелкими - равными. Убедитесь, что все, от чего renderItemзависит ваша функция, передается как опора, которая не ===после обновлений, иначе ваш пользовательский интерфейс может не обновляться при изменениях. Это включает в себя состояние dataопоры и родительского компонента ". Вы следуете этому совету?
Jordan Running

3
Независимо от того, что я пробовал с extraDataи shouldItemUpdate, я не мог получить список для повторной визуализации. В итоге я очистил состояние, дождался его рендеринга и затем обновил состояние. this.setState({ data: null }, () => { this.setState({ data: actualData }) });
Джошуа Пинтер

Ответы:


186

Используйте extraDataсвойство в своем компоненте FlatList.

Как указано в документации:

Переходя extraData={this.state}к, FlatListмы гарантируем, что FlatListбудет повторно отрисовываться при state.selectedизменении. Без установки этой опоры FlatListне будет знать, что ей нужно повторно отрисовать какие-либо элементы, потому что она также является a, PureComponentи сравнение опоры не покажет никаких изменений.


34
Я использую redux и в этом случае отправляю данные вроде data={this.props.searchBookResults}и extraData={this.state}ни extraData={this.props}у меня, ни у меня не работает. И data={this.props.searchBookResults}тоже не работает. Что делать ?
Sujit

8
Используйте extraData: чтобы обновить ваш <FlatList>... data={this.props.searchBookResults} extraData={this.state.refresh} onPress={()={this.setState({ refresh: !refresh})}
Нет

9
Я борюсь с той же проблемой. Неважно, что я extraData
передаю

2
@DenisCappelini, убедитесь, что данные, передаваемые в extraDataопору, изменяются, когда дочерний элемент [ы] должен повторно отображаться. Например, если элементы списка могут быть активными / неактивными, убедитесь, что эта переменная статуса, независимо от того, является ли часть this.stateобъекта или this.propsобъект тем, что должно быть внутри extraData. Это может быть курсор или массив активных элементов и т. Д.
Emperor_Earth

1
@Sujit Я столкнулся с той же проблемой, но затем я понял, что реализовал shouldComponentUpdate(), как только я обновил это или полностью закомментировал, все работало так же, как описано в документации.
JanithaR

51

Для быстрого и простого решения Попробуйте:

  1. установить дополнительные данные в логическое значение.

    extraData = {this.state.refresh}

  2. Переключите значение логического состояния, когда вы хотите повторно отрисовать / обновить список

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

Это именно то, что мне нужно, поскольку я буду добавлять данные в опору данных. Кроме того, это очень странная реализация команды React-Native ... было бы разумнее иметь функцию или свойство обновления данных. IE: this.data.refresh(). Вместо этого мы устанавливаем логическое значение и меняем его. Само логическое значение не имеет смысла, так какой смысл в нем существовать? ... (Нет смысла, кроме как правильно обновлять данные?)
YungGun 01

@HradeshKumar Я делаю это, но последний элемент данных не может исчезнуть!
DevAS

это работает как шарм, но я до сих пор не знаю, почему this.state.usersне работает, хотя я менял флаг у некоторых пользователей.
shyammakwana.me

21

О, это просто, просто используйте extraData

Вы видите, как дополнительные данные работают за кулисами: FlatList или VirtualisedList просто проверяют , изменился ли этот объект с помощью обычного onComponentWillReceivePropsметода.

Итак, все, что вам нужно сделать, это убедиться, что вы добавили что-то, что меняет файл extraData.

Вот что я делаю:

Я использую immutable.js, поэтому все, что я делаю, это передаю Map (неизменяемый объект), содержащий все, что я хочу посмотреть.

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

Таким образом, при изменении this.props.fooили this.props.barизменении наш CustomComponentRowбудет обновляться, потому что неизменяемый объект будет отличаться от предыдущего.


2
я наконец понял extraData! спасибо за ссылку на VirtualisedListкод!
Тушар Коул

привет, @ SudoPiz Я хочу повторно отрендерить Flatlist после удаления последнего элемента, могу проверить этот Q stackoverflow.com/questions/58780167/…
Оливер Д.

6

Хорошо, я только что узнал, что если мы хотим, чтобы FlatList знал об изменении данных за пределами свойства данных, нам нужно установить его на extraData, поэтому я делаю это сейчас так:

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

обратитесь к: https://facebook.github.io/react-native/docs/flatlist#extradata


1
Лучшая реализация ... Я предпочел установить его как опору данных, чтобы она не обновлялась, когда что-либо в состоянии изменяется, но это САМАЯ ЛЕГКАЯ реализация на сегодняшний день. Благодарность!
Роберт Кехо

привет, @MahdiBashirpour, я хочу повторно отрендерить Flatlist после удаления последнего элемента, могу проверить этот Q stackoverflow.com/questions/58780167/…
Оливер Д.

4

Если у вас будет Button, вы можете обновить данные с помощью setState внутри onPress. SetState затем повторно отобразит ваш FlatList.


2
в моем touchhighlight есть setState. setState работает нормально, но плоский список не показывает обновление значения состояния -> this.state.value
shalonteoh

Значения в вашем FlastList не обновляются, потому что вы не обновляете источник данных напрямую. this.state.data - это то, что отображается с помощью FlatList, но в onPress вы обновляете только this.state.value.
WilliamC

извините за ошибку, опечатку в вопросе. должно быть this.state.data [index] .value
shalonteoh

3

После долгих поисков и поиска настоящего ответа, наконец, я получил ответ, который я считаю лучшим:

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

Моя основная проблема заключалась в том, что (KeyExtractor) я не использовал его таким образом. не работает: keyExtractor = {(item) => item.ID} после того, как я перешел на это, он работал как шарм, надеюсь, это кому-то поможет.


вы можете указать значение this.state.refreshingи функцию handleRefresh?
DevAS

1

Я решил эту проблему, добавив. extraData={this.state}Пожалуйста, проверьте код ниже, чтобы получить более подробную информацию.

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

1

Просто расширение предыдущих ответов здесь. Две части для обеспечения: убедитесь, что вы добавили extraData и что ваш keyExtractor уникален. Если ваш keyExtractor постоянный, повторная визуализация не будет запущена.

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

0

Я заменил FlatListна, SectionListи он правильно обновляется при изменении состояния.

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

Единственное, что нужно иметь в виду, это sectionналичие структуры diff:

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

0

Для меня трюк заключался в extraData и еще раз углублении в компонент элемента

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

Поместите переменные, которые будут изменены при вашем взаимодействии, в extraData

Вы можете быть творческими.

Например, если вы имеете дело с изменяющимся списком с флажками на них.

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

0

Если мы хотим, чтобы FlatList знал, что данные меняют свойство и состояние , мы можем создать объект, ссылающийся как на свойство, так и на состояние, и обновить плоский список.

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

Документы: https://facebook.github.io/react-native/docs/flatlist#extradata


0

В react-native-flatlist это свойство, называемое extraData. добавьте строку ниже в свой плоский список.

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

0

В этом примере, чтобы принудительно выполнить повторный рендеринг, просто измените переменную machine

const [selected, setSelected] = useState(machine)

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

-1

Просто используйте:

onRefresh={true}

внутри вашего flatListкомпонента.


1
это создает ошибку, тогда вам нужно использовать refreshingопору
mahmoudafer

-1

ExtraData Flatlist не работал у меня, и я использовал опору от redux. Это звучало похоже на вопросы из комментариев в ответе ED209. Я закончил тем, что вручную вызвал setState, когда получил опору.

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

Для тех из вас, кто использует> React 17, используйте getDerivedStateFromProps

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.