FlatList перерисовывает каждый раз, когда я набираю что-то в TextInput - PullRequest
0 голосов
/ 22 мая 2018

Я не думаю, что это ошибка, больше похоже, что я делаю что-то не так, но здесь все идет.Я создаю компонент чата для своего приложения, это очень просто, я набираю что-то и нажимаю кнопку отправки, добавляет в список и отображает.Несколько дней назад я обнаружил, что если бы я начал печатать большие и быстрые сообщения, мой JS FPS упал бы до 10, 5 и 1, и я узнал сегодня благодаря реализации отображения данных / времени для сообщений, которые каждый раз, когда я что-то печатаю в TextInputи запустите событие onChangeText и измените состояние «text», оно перерисовывает ВСЕ элементы внутри моего FlatList

Вот мой код:

Компонент чата:

<FlatList
    key={'chat'}
    ref={(ref) => {flatlistRef = ref}}
    style={styles.flatlist_main}
    data={this.state.items}
    extraData={this.state}
    renderItem={this.renderItem}
    keyExtractor={this.keyExtractor}
    onContentSizeChange={(contentWidth, contentHeight) => {
          flatlistRef.scrollToEnd({animated: true});
    }}
    onLayout={() => {flatlistRef.scrollToEnd({animated: true})}}
/>

Функция onChangedText

onFooterTextChanged = (text) => {
    this.setState({
        text: text,
        options_expanded: false,
    });
};

Функция кнопки onSendMessage

onSendButtonPressed = () => {
    if(this.state.text !== null && this.state.text !== "") {
        this.setState({
            items: [
                ...this.state.items,
                {
                    id: moment().valueOf(),
                    text: this.state.text,
                    date: moment().valueOf(),
                    user: {
                        id: globals.user_id_value,
                        avatar: globals.user_photo,
                    }
                }
            ],
            text: "",
            options_expanded: true,
        });
    }
};

Функция renderItem для FlatList

renderItem = (item) => {
    const data = item.item;
    const renderAvatar = this.renderAvatar(item);
    const renderTime = this.renderTime(item);
    if('text' in data){
        return(
            <ChatTextItem
                keyy={data.id}
                self={globals.user_id_value === data.user.id}
                text={data.text}
                user={data.user}
                renderAvatar={renderAvatar}
                sameUser={!renderAvatar}
                renderTime={renderTime}
                time={this.getTime(data.date)}
            />
        )
    } else if('image' in data) {
        return(
            <ChatImageItem
                keyy={data.id}
                self={globals.user_id_value === data.user.id}
                image={data.image}
                renderAvatar={renderAvatar}
                sameUser={!renderAvatar}
                renderTime={renderTime}
                time={this.getTime(data.date)}
            />
        )
    }
};

Конструктор, если он помогает

constructor(props){
    super(props);
    this.state = {
        isLoading: false,
        options_expanded: true,
        text: "",
        image: "",
        items: [],
    };
}

и я пользователь PureComponent, кстати.

Редактировать # 1: Консоль после ввода, как сумасшедший в TextInput enter image description here Она перерисовала 28 раз для 28 букв, которые я набрал, и этоделает ли это * количество элементов в списке уже

Редактировать # 2: Изменения, внесенные в файл JS

Изменен параметр ExtraData FlatList

 <FlatList
      key={'chat'}
      ref={(ref) => {flatlistRef = ref}}
      style={styles.flatlist_main}
      data={this.state.items}
      extraData={this.state.refresh}
      renderItem={this.renderItem}
      keyExtractor={this.keyExtractor}
      onContentSizeChange={(contentWidth, contentHeight) => {
            flatlistRef.scrollToEnd({animated: true});
      }}
      onLayout={() => {flatlistRef.scrollToEnd({animated: true})}}
  />

и изменен конструктордобавить обновление State

 constructor(props){
    super(props);
    this.state = {
        isLoading: false,
        options_expanded: true,
        text: "",
        image: "",
        items: [],
        refresh: false,
    };
}

Проблема по-прежнему сохраняется

Редактировать: # 3 Наконец-то найдена проблема

Работает

<FlatList
                key={'chat'}
                ref={(ref) => {flatlistRef = ref}}
                style={styles.flatlist_main}
                data={this.state.items}
                extraData={this.state.refresh}
                renderItem={this.renderItem}
                keyExtractor={this.keyExtractor}

            />

не работает

 <FlatList
                key={'chat'}
                ref={(ref) => {flatlistRef = ref}}
                style={styles.flatlist_main}
                data={this.state.items}
                extraData={this.state.refresh}
                renderItem={this.renderItem}
                keyExtractor={this.keyExtractor}
                onContentSizeChange={(contentWidth, contentHeight) => {
                    flatlistRef.scrollToEnd({animated: true});
                }}
                onLayout={() => {flatlistRef.scrollToEnd({animated: true})}}
            />

Есть идеи почему?Пожалуйста!

Если бы кто-то мог помочь мне найти решение моей проблемы, я был бы признателен.

Ответы [ 3 ]

0 голосов
/ 22 мая 2018

Похоже, это из-за того, что вы extraData получили все состояние

Это PureComponent, что означает, что он не будет повторно визуализироваться, если реквизит остается мелко-равным.Убедитесь, что все, от чего зависит ваша функция renderItem, передается как реквизит (например, extraData), который не === после обновлений, иначе ваш пользовательский интерфейс может не обновляться при изменениях.Это включает в себя реквизит данных и состояние родительского компонента

Так что это ожидаемое поведение, поскольку вы обновляете свое состояние каждый раз, когда пользователь вводит данные в поле ввода.

Кроме того, FlatList долженотображать (или повторно отображать) только элементы, видимые на экране

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

Попробуйте исправить extraData.Что-то вроде extraData={this.state.refresh}, где this.state.refresh обновляется, когда пользователь нажимает кнопку send.

Подробнее здесь: https://facebook.github.io/react-native/docs/flatlist.html

Надеюсь, это поможет

0 голосов
/ 22 мая 2018

Очевидно, что если я удаляю события onLayout и onContentSizeChanged из моего FlatList, он останавливает рендеринг при любых изменениях состояния и только состояние, предоставленное в extraData, все равно не решает мою проблему, и это удивительно ухудшает производительность,Спасибо всем, кто помог решить эту проблему.

0 голосов
/ 22 мая 2018

Я не думаю, что это ошибка, это то, что нам нужно для вашего чата.Поскольку вы обновляли состояние для каждого onPress (onSendButtonPressed), чтобы показать новое сообщение в списке.Таким образом, он повторно отображает список.Может быть, то, что я предлагаю, это просто показать последние сообщения в своем плоском списке.т.е. последние 3 или 4 дня сообщение в flatList и загружается больше, когда пользователь идет назад более 4 дней.Это поможет вам улучшить производительность вашего чата.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...