1. ホーム
  2. ジャバスクリプト

[解決済み】Reactで子の状態にアクセスする方法

2022-03-31 08:32:19

質問

以下のような構造になっています。

FormEditor - は、FieldEditor の複数のインスタンスを保持します。 FieldEditor - はフォームのフィールドを編集し、そのフィールドに関するさまざまな値をステートに保存します。

FormEditorの中でボタンがクリックされたとき、フィールドに関する情報をすべての FieldEditor コンポーネントの状態に関する情報を、すべてFormEditor内に持っています。

の外側にフィールドの情報を格納することを検討しました。 FieldEditor の状態にして、それを FormEditor の状態になります。しかし、そのためには FormEditor をそれぞれリッスンする必要があります。 FieldEditor コンポーネントを変更し、その情報をステートに格納します。

代わりにchildrenのstateにアクセスすることはできないのでしょうか?それは理想的なことですか?

どのように解決するのですか?

もしあなたがすでに個々のFieldEditorにonChangeハンドラを持っているなら、状態をFormEditorコンポーネントに移動して、そこからFieldEditorにコールバックを渡して親の状態を更新することができない理由がわからない。その方がよりReactらしい方法だと思います。

このような感じでしょうか。

const FieldEditor = ({ value, onChange, id }) => {
  const handleChange = event => {
    const text = event.target.value;
    onChange(id, text);
  };

  return (
    <div className="field-editor">
      <input onChange={handleChange} value={value} />
    </div>
  );
};

const FormEditor = props => {
  const [values, setValues] = useState({});
  const handleFieldChange = (fieldId, value) => {
    setValues({ ...values, [fieldId]: value });
  };

  const fields = props.fields.map(field => (
    <FieldEditor
      key={field}
      id={field}
      onChange={handleFieldChange}
      value={values[field]}
    />
  ));

  return (
    <div>
      {fields}
      <pre>{JSON.stringify(values, null, 2)}</pre>
    </div>
  );
};

// To add the ability to dynamically add/remove fields, keep the list in state
const App = () => {
  const fields = ["field1", "field2", "anotherField"];

  return <FormEditor fields={fields} />;
};

オリジナル - プリフックバージョン。

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 a class component and add the ability 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);