У меня есть компонент («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.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 - просто используйте реквизиты. Вы можете увидеть рабочие коды и ящик здесь.
На самом деле в моем фактическом коде вместо <input> у меня есть компонент ввода, который является управляемым компонентом, и передача ему реквизита для значения делает его недоступным для редактирования, поэтому я передаю ему значение состояния. Я все еще получаю тот же неправильный вывод.
К сожалению, я не могу поделиться своим реальным кодом. Но хорошая новость в том, что я смог разобраться в проблемах. В основном они были вызваны использованием состояния вместо реквизита для атрибутов значения. Таким образом, решение было такого рода: <input value = {this.props ...} onChange = {} вместо <input value = {this.state ...}, как в моем коде выше. Я новичок и благодарен за ваши исправления, такие как неизменное изменение значений массива, которое вы показали выше, чтобы React мог обнаружить изменение состояния. Спасибо!
Исправление проблем произошло с использованием этого кода:
<input value = {this.props....} onChange = {...} // first version
вместо того
<input value = {this.state....} onChange = {....} // second version
Раньше я думал, что вторая версия верна и что первая версия не позволяла редактировать ввод. Но похоже, что наличие onChange заставило первую версию работать (правильно отображая исходные и отредактированные значения и позволяя редактировать)
Спасибо @Volodymyr, у меня есть super (props) в моем коде, но я добавил их выше. Я также использовал ваш шаблон кода для добавления элемента к моему массиву. Но мне нужен <input>, редактируемый пользователем, и это не работает: <input value = {this.props.details.prop1} ...>, но это работает: <input value = {this.state.details .prop1} ...>. Я все еще получаю неправильный результат.