ReactJS: неправильный рендеринг списка компонентов

У меня есть компонент («ComponentA»), который несколько раз отображается в map () внутри render () другого компонента («ComponentB»).

Кроме того, у меня есть кнопка «ДОБАВИТЬ» в ComponentB, которая при нажатии добавляет (через метод unshift ()) объект в массив «state.objects» своего ComponentB (используемый для сопоставления экземпляров ComponentA). Каждый добавленный объект имеет свойство prop1, которое я установил для входного текстового значения ComponentA.

Проблема в том, что я не получал ожидаемых значений в состоянии каждого экземпляра ComponentA: во всех случаях элемент всегда имеет значение «1» (я ожидаю ... 3, 2, 1).

Более того, я вижу, что конструктор ComponentA вызывается только один раз в каждом цикле сопоставления и, в частности, непосредственно перед вызовом render () для последнего экземпляра.

Вот (упрощенный) код:

    class ComponentB extends Component {
      constructor(props) {
        super(props) // added upon first reply
        this.handleObjectAdd = this.handleObject.bind(this);
        this.state.objects = [];
      }

      handleObjectAdd() {
        this.state.objects.unshift({prop1: this.state.objects.length + 1});
      }

      render() {
          return (
            <div>
              <button onClick = {this.handleObjectAdd}>ADD</button>
              { this.state.objects.map((object, index) =>
                  <ComponentA key = {index} details = {object}/>
                )
              }
            </div>
          )
        })
      }
    }

    class ComponentA extends Component {
      constructor(props) {
        super(props) // added upon first reply
        console.info('ComponentA constructor called');
        this.state = { details: props.details };
      }
      render() {
        console.info('ComponentA render() called, prop1 value is ' + this.state.details.prop1);
        return (
          <input type = "text" value = {this.state.details.prop1}></input>
        )
      }
    }

Итак, с помощью приведенного выше кода нажатие кнопки ДОБАВИТЬ один раз регистрирует следующее:

    ComponentA constructor called
    ComponentA render() called, prop1 value is 1

Нажатие на кнопку 2 раза регистрирует:

    ComponentA render() called, prop1 value is 1
    ComponentA constructor called'
    ComponentA render() called, prop1 value is 1

При третьем нажатии на кнопку регистрируются:

    ComponentA render() called, prop1 value is 1
    ComponentA render() called, prop1 value is 1
    ComponentA constructor called'
    ComponentA render() called, prop1 value is 1

... и так далее.

Во всех экземплярах ComponentA вводимое текстовое значение равно «1».

Мои вопросы:

1) Как мне его закодировать, чтобы получить желаемое возрастающее значение для ComponentA?

2) Почему конструктор сопоставленного компонента вызывается только один раз и в этой конкретной позиции (непосредственно перед последним визуализированным экземпляром)?

ЗАМЕТКА: Приведенный выше код - это просто упрощенная версия моего фактического кода, показывающая только основные части для демонстрации проблемы.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
77
2

Ответы 2

Вы никогда не следует изменять состояние напрямую, выполняя что-то вроде this.state.objects.unshift() - вместо этого используйте this.setState(). Когда вы изменяете массив или объект внутри this.state напрямую, React не знает, что какое-то значение внутри него было изменено. Это отвечает на оба ваших вопроса. Таким образом, вместо прямого изменения this.state.objects:

this.state.objects.unshift({prop1: this.state.objects.length + 1});

вы должны добавить новый элемент к массиву неизменным способом:

const newItem = { prop1: this.state.objects.length + 1 };
this.setState({
  objects: [newItem].concat(this.state.objects)
});

Кроме того, вы забыли вызвать super(props) внутри конструкторов ComponentA и ComponentB. Кроме того, нет необходимости копировать переданные реквизиты в состояние компонентов внутри ComponentA - просто используйте реквизиты. Вы можете увидеть рабочие коды и ящик здесь.

Спасибо @Volodymyr, у меня есть super (props) в моем коде, но я добавил их выше. Я также использовал ваш шаблон кода для добавления элемента к моему массиву. Но мне нужен <input>, редактируемый пользователем, и это не работает: <input value = {this.props.details.prop1} ...>, но это работает: <input value = {this.state.details .prop1} ...>. Я все еще получаю неправильный результат.

Nodelay Heehoo 26.10.2018 01:30

На самом деле в моем фактическом коде вместо <input> у меня есть компонент ввода, который является управляемым компонентом, и передача ему реквизита для значения делает его недоступным для редактирования, поэтому я передаю ему значение состояния. Я все еще получаю тот же неправильный вывод.

Nodelay Heehoo 26.10.2018 01:36

К сожалению, я не могу поделиться своим реальным кодом. Но хорошая новость в том, что я смог разобраться в проблемах. В основном они были вызваны использованием состояния вместо реквизита для атрибутов значения. Таким образом, решение было такого рода: <input value = {this.props ...} onChange = {} вместо <input value = {this.state ...}, как в моем коде выше. Я новичок и благодарен за ваши исправления, такие как неизменное изменение значений массива, которое вы показали выше, чтобы React мог обнаружить изменение состояния. Спасибо!

Nodelay Heehoo 29.10.2018 21:39

Исправление проблем произошло с использованием этого кода:

    <input value = {this.props....} onChange = {...} // first version

вместо того

    <input value = {this.state....} onChange = {....} // second version

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

Другие вопросы по теме