Мое предложение состоит в том, чтобы исходить из обработчика onChange, и код можно понять немного проще.
В основном React не обновляет состояние сразу после вызова setState()
, он выполняет пакет работа. Поэтому может случиться так, что несколько вызовов setState
обращаются к одной контрольной точке. Если вы напрямую изменяете состояние, это может вызвать хаос, так как другое состояние может использовать обновленное состояние при выполнении пакетного задания.
Кроме того, если вы обработали обработчик source onChange на уровне приложения, вы можете изменить MetafieldInputs на функциональный компонент, а не компонент баз классов. Функциональный компонент стоит меньше, чем компонентный класс, и может повысить производительность.
Ниже приведен проверенный обновленный код. Я предполагаю, что вы используете TextField пользовательского интерфейса для материала, но onChangeHandler также должен работать в вашем собственном компоненте.
// Full App.js
import React, { Component } from 'react';
import MetafieldInputs from './MetafieldInputs';
class App extends Component {
state = {
metafields: [
{
metafield:
{
namespace: "namespaceVal",
key: "keyVal",
val: [
{ '0': "val1" },
{ '1': "val2" },
{ '2': "val3" }
]
}
},
]
}
// will never be triggered as from React point of view, the state never changes
componentDidUpdate() {
console.log('componentDidUpdate')
}
render() {
const metafields = this.state.metafields;
const metafieldsKeys = Object.keys(metafields);
const renderInputs = metafieldsKeys.map(key => {
const metafield = metafields[key];
return <MetafieldInputs metafields={metafield.metafield.val} key={metafield.metafield.key} />;
})
return (
<div>
{renderInputs}
</div>
)
}
}
export default App;
// full MetafieldInputs
import React, { Component } from 'react'
import TextField from '@material-ui/core/TextField';
class MetafieldInputs extends Component {
state = {
metafields: this.props.metafields
}
onChangeHandler = (e, index) => {
const value = e.target.value;
this.setState(prevState => {
const updateMetafields = [...prevState.metafields];
const updatedFields = { ...updateMetafields[index] }
updatedFields[index] = value
updateMetafields[index] = updatedFields;
return { metafields: updateMetafields }
})
}
render() {
const { metafields } = this.state;
// will always remain the same
console.log('this.props', this.props)
return (
<div>
{metafields.map((meta, i) => {
return (
<TextField
value={meta[i]}
changekey={meta}
onChange={(e) => this.onChangeHandler(e, i)}
// generally it is not a good idea to use index as a key.
key={i}
/>
)
}
)}
</div>
)
}
}
export default MetafieldInputs
Опять же, ЕСЛИ у вас есть класс onChangeHandler
- App
, MetafieldInputs
может быть чистым функциональный компонент, и все управление состоянием может быть выполнено в классе App
.
С другой стороны, если вы хотите сохранить чистый и чистый класс App
, вы также можете хранить метаполя в MetafieldInputs. Класс в случае, если вам может понадобиться другой лог c в вашем приложении.
Например, ваше приложение отображает больше компонентов, чем в примере, и MetafieldInputs не следует отображать, пока что-то не произойдет. Если вы извлекаете данные со стороны сервера, лучше извлекать данные, когда они необходимы, а не извлекать все данные в компоненте приложения.