Реагирование на памятку элемента родного списка - PullRequest
0 голосов
/ 06 октября 2019

Я пытаюсь предотвратить ненужные отрисовки FlatList элементов, используя React.memo(), но я столкнулся с некоторым странным поведением. обратный вызов, который обеспечивает предыдущие реквизиты и последующие реквизиты, всегда имеет одинаковое значение, даже если они изменились выше по цепочке.

export default React.memo(PersonCell, (prev, next) => {
  reactotron.log(`prev ${prev.person.name}: is checked${prev.person.isChecked}`)
  reactotron.log(`next ${next.person.name}: is checked${next.person.isChecked}`)
  return prev.person.isChecked === next.person.isChecked
})

Цепочка, которую я имею, я использую Realm с оченьпростая структура {id:number, name:string, isChecked:boolean} и всякий раз, когда они касаются ячейки, она будет записывать в область, на верхнем уровне приложения у меня есть прослушиватель изменений данных, а затем устанавливается состояние для передачи его обратно в список

let [data, setData] = useState([]);

  useEffect(() => {
    let sub = person$.subscribe({
      next: collection => {
        reactotron.logImportant!(collection)
        setData([...data, ...collection.map(x => x)]);
      },
    });

вот код клетки

import React from 'react';
import { Subject } from "rxjs";
import { useEffect } from "react";
import realm, { PersonSchema } from "./realm";
import { Person } from "./PersonsList";
import { View, TouchableOpacity, Text } from "react-native";
import reactotron from 'reactotron-react-native';

interface Props {
  person: Person
}
const onCheck$ = new Subject<number>();
const PersonCell: React.FC<Props> = props => {

  useEffect(() => {
    let sub = onCheck$.subscribe({
      next: x => {
        realm.write(() => {
          let person = realm.objectForPrimaryKey<Person>(PersonSchema.name, x);
          if (!person) return;
          person.isChecked = !person.isChecked;
        });
      },
    });
    return () => sub.unsubscribe;
  }, []);

  return (
    <View>
      <Text>{props.person.name}</Text>
      <TouchableOpacity onPress={() => onCheck$.next(props.person.id)}>
        <View
          style={{
            backgroundColor: props.person.isChecked
              ? 'rgb(255,1,1)'
              : 'rgb(1,1,255)',
            width: 20,
            height: 20,
          }}
        />
      </TouchableOpacity>
    </View>
  );
};

PersonCell.whyDidYouRender = true;

// export default React.memo(PersonCell)
export default React.memo(PersonCell, (prev, next) => {
  reactotron.log(`prev ${prev.person.name}: is checked${prev.person.isChecked}`)
  reactotron.log(`next ${next.person.name}: is checked${next.person.isChecked}`)
  return prev.person.isChecked === next.person.isChecked
})

Это ожидаемое поведение или я что-то не так делаю? Вот репо того, что я объясняю

Обновление

Я удалил плоский список и использовал базовую карту и ключ, чтобы сгенерировать список предметов, и проблема выше по-прежнемуПоявились текущие реквизиты, а переданные реквизиты во втором параметре shouldComponentUpdate и React.memo остались прежними, несмотря на их изменение.

здесь есть ссылка изпарень испытывает нечто подобное

1 Ответ

0 голосов
/ 08 октября 2019

Я полагаю, что проблема возникла из-за того, что состояние не изменялось. я полагал, что этого

let sub = person$.subscribe({
      next: collection => {
        setData(collection.map(x => x));
      },
    });

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

let sub = person$.subscribe({
      next: collection => {
        setData(collection.map(x => x).map(x => _.toPlainObject(x)));
      },
    });

т.е. сделать глубокий клон каждого объекта, возвращаемого из области, чтобы он работал правильно ... Или, возможно, есть проблема с машинописью.

Если кто-то хочет присоединиться к более краткому ответу, мы приветствуем вас.

В любом случае в репо вносятся изменения, если кто-то захочет взглянуть на него.

...