У меня есть следующая структура:
FormEditor
- содержит несколько FieldEditor
FieldEditor
- редактирует поле формы и сохраняет в нем различные значения. Состояние
При нажатии кнопки в FormEditor я хочу иметь возможность собирать информацию о полях из всех компонентов FieldEditor
, информацию, которая находится в их состоянии, и иметь все это в FormEditor.
Я рассмотрел сохранение информации о полях вне состояния FieldEditor
и вместо этого поставил ее в состояние FormEditor
. Однако для этого требуется FormEditor
прослушать каждый из них FieldEditor
, поскольку они меняются и сохраняют в нем свою информацию.
Не могу ли я просто получить доступ к состоянию детей? Идеально?
Если у вас уже есть обработчик onChange для отдельных FieldEditors, я не понимаю, почему вы не могли просто переместить состояние в компонент FormEditor и просто передать обратный вызов оттуда в FieldEditors, который обновит родительское состояние. Мне кажется, это более эффективный способ сделать это.
Возможно, что-то в этом роде:
class FieldEditor extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
const text = event.target.value;
this.props.onChange(this.props.id, text);
}
render() {
return (
<div className="field-editor">
<input onChange={this.handleChange} value={this.props.value} />
</div>
);
}
}
class FormEditor extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.handleFieldChange = this.handleFieldChange.bind(this);
}
handleFieldChange(fieldId, value) {
this.setState({ [fieldId]: value });
}
render() {
const fields = this.props.fields.map(field => (
<FieldEditor
key={field}
id={field}
onChange={this.handleFieldChange}
value={this.state[field]}
/>
));
return (
<div>
{fields}
<div>{JSON.stringify(this.state)}</div>
</div>
);
}
}
// Convert to class component and add abillity to dynamically add/remove fields by having it in state
const App = () => {
const fields = ["field1", "field2", "anotherField"];
return <FormEditor fields={fields} />;
};
ReactDOM.render(<App />, document.body);
http://jsbin.com/qeyoxobixa/edit?js,output
Редактировать: Вместо того, чтобы передавать элементы FieldEditor как дочерние в FormEditor, я просто передаю список fieldIds и создаю их вместо этого в FormEditor. Это упрощает динамическое добавление FieldEditor и делает метод визуализации FormEditor менее удачным.
myAPI.SaveStuff(this.state);
, Если вы уточните немного больше, может быть, я могу дать вам лучший ответ :)
Непосредственно перед тем, как я подробно расскажу о том, как вы можете получить доступ к состоянию дочернего компонента, обязательно прочитайте ответ Markus-ipse относительно лучшего решения для этого конкретного сценария.
Если вы действительно хотите получить доступ к состоянию дочерних компонентов, вы можете назначить свойство ref
с именем каждого дочернего элемента. Теперь есть два способа реализации ссылок: использование React.createRef()
и обратного вызова refs.
React.createRef()
В настоящее время это рекомендуемый способ использования ссылок с React 16.3 (дополнительную информацию см. В документации). Если вы используете более раннюю версию, то смотрите ниже ссылки обратного вызова.
Вам нужно будет создать новую ссылку в конструкторе вашего родительского компонента, а затем назначить ее дочернему элементу через атрибут ref
.
class FormEditor extends React.Component {
constructor(props) {
super(props);
this.FieldEditor1 = React.createRef();
}
render() {
return <FieldEditor ref={this.FieldEditor1} />;
}
}
Чтобы получить доступ к этому виду ссылки, вам нужно использовать:
const currentFieldEditor1 = this.FieldEditor1.current
Это вернет экземпляр смонтированного компонента, поэтому вы можете использовать currentFieldEditor1.state
для доступа к состоянию.
Просто заметьте, что если вы используете там ссылки на узле DOM вместо компонента (например, <div ref={this.divRef}/>
), то this.divRef.current
вернет базовый элемент DOM вместо компонента пример.
Это свойство принимает функцию обратного вызова, которой передается ссылка на присоединенный компонент. Этот обратный вызов выполняется сразу после монтирования или демонтажа компонента.
Например:
<FieldEditor
ref={(fieldEditor1) => {this.fieldEditor1 = fieldEditor1;}
{...props}
/>
В этих примерах ссылка хранится на родительском компоненте. Чтобы вызвать этот компонент в своем коде, вы можете использовать:
this.fieldEditor1
а затем используйте this.fieldEditor1.state
чтобы получить состояние.
Прежде всего, убедитесь, что ваш дочерний компонент отрендерен, прежде чем пытаться получить к нему доступ ^ _ ^
Если вы хотите узнать больше о недвижимости React, проверьте эту страницу на Facebook.
Обязательно прочитайте раздел " Не злоупотребляйте ссылками ", в котором говорится, что вы не должны использовать дочернее state
чтобы "что-то происходило".
Надеюсь, это поможет ^ _ ^
Редактировать: Добавлен React.createRef()
для создания ссылок. Удален код ES5.
this.refs.yourComponentNameHere
. Я нашел это полезным для изменения состояния с помощью функций. Пример: this.refs.textInputField.clearInput();
props
и state
. Однако они не должны быть вашей основной абстракцией для передачи данных через ваше приложение. По умолчанию используйте Поток данных Reactive и сохраняйте ref
для случаев использования, которые по своей природе не являются реактивными.
Теперь вы можете получить доступ к состоянию InputField, которое является дочерним по отношению к FormEditor.
По сути, всякий раз, когда происходит изменение состояния поля ввода (дочернего), мы получаем значение из объекта события и затем передаем это значение в Parent, где устанавливается состояние в Parent.
При нажатии кнопки мы просто печатаем состояние полей ввода.
Ключевым моментом здесь является то, что мы используем реквизиты для получения идентификатора/значения поля ввода, а также для вызова функций, которые задаются как атрибуты в поле ввода, в то время как мы генерируем многократно используемые дочерние поля ввода.
class InputField extends React.Component{
handleChange = (event)=> {
const val = event.target.value;
this.props.onChange(this.props.id , val);
}
render() {
return(
<div>
<input type="text" onChange={this.handleChange} value={this.props.value}/>
<br/><br/>
</div>
);
}
}
class FormEditorParent extends React.Component {
state = {};
handleFieldChange = (inputFieldId , inputFieldValue) => {
this.setState({[inputFieldId]:inputFieldValue});
}
//on Button click simply get the state of the input field
handleClick = ()=>{
console.log(JSON.stringify(this.state));
}
render() {
const fields = this.props.fields.map(field => (
<InputField
key={field}
id={field}
onChange={this.handleFieldChange}
value={this.state[field]}
/>
));
return (
<div>
<div>
<button onClick={this.handleClick}>Click Me</button>
</div>
<div>
{fields}
</div>
</div>
);
}
}
const App = () => {
const fields = ["field1", "field2", "anotherField"];
return <FormEditorParent fields={fields} />;
};
ReactDOM.render(<App/>, mountNode);