从不传递 Props 的 Child 组件表单获取输入?

Get Inputs From Child Component Form That Doesn't Pass Props?

在下面的 Parent 组件中,我有一个包含两个选项的下拉列表。如果您 select "TOP LEVEL",那么将显示一个名为 Form1 的表单。如果我选择 "MAKE ITEM",那么将显示一个名为 Form2 的表单。如果什么都不 selected 则两种形式都被隐藏。我的 Parent 组件中有一个按钮,我想提交显示的当前表单中的任何输入。因此,如果 "TOP LEVEL" 被 selected,并且单击了按钮,我想记录来自 Form1 的输入。这可能吗?还是我需要将所有内容都放在一个组件中?如果可能的话,我需要使用 Formik 吗?如果我处理这个错误,请提出更好的方法。

Parent 组件

import * as React from "react";
import { Dropdown, DropdownMenuItemType, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import { PrimaryButton } from 'office-ui-fabric-react/lib/';
import Form1 from './Form1';
import Form2 from './Form2';
export interface ParentProps {
};

export interface ParentState  {
  selectedItem?: { key: string | number | undefined };
  operationType?;
  formName?
};

export default class ParentComponent extends React.Component<ParentProps, ParentState> {
  constructor(props, context) {
    super(props, context);
    this.state = {
      operationType: '',
      formName: '',
    };
  }
  addToExcel = async () => {
    try {
      await Excel.run(async context => {
        const range = context.workbook.getSelectedRange();
        range.load("address");
        await context.sync();
        console.log(`The range address was ${range.address}.`);
      });
    } catch (error) {
      console.error(error);
    }
    this.setState({
      operationType: '',
    })
  };
render(){
  const { selectedItem } = this.state;
  const options: IDropdownOption[] = [
      { key: 'blank', text: '' },
      { key: 'topLevelMake', text: 'Parents', itemType: DropdownMenuItemType.Header },
      { key: 'topLevel', text: 'TOP LEVEL' },
      { key: 'make', text: 'MAKE ITEM' },
    ];
    return(
    <div>
        <Dropdown
            label="Operation"
            selectedKey={selectedItem ? selectedItem.key : undefined}
            onChange={this._onChange}
            placeholder={"Select an option"}
            options={options}
            styles={{ dropdown: { width: 300 } }}
        />
        {this.state.formName}  
        <p></p>
        <PrimaryButton 
            text="Enter"
            onClick={this.addToExcel}
        />
    </div>
      );
   }
   private _onChange = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption): void => {
    this.setState({ selectedItem: item });
    this.setState({operationType: item.text})
    console.log(event);
    let Form = <div />;
    switch (item.text) {

      case "TOP LEVEL":
        Form = <Form1 /> ;
        this.setState({formName: Form});
        break;

      case "MAKE ITEM":
        Form = <Form2 /> ;
        this.setState({formName: Form});
      break;


      default:
        Form = <div></div>
      break;
    }
  };
}

Form1(Form2类似所以我不包括)

import * as React from "react";
import { TextField } from 'office-ui-fabric-react/lib/';
export interface Form1Props {
};
export interface Form1State  {
  dataGoToExcel?;
  dataGoToExcel2?;
};
export default class Form1 extends React.Component<Form1Props, Form1State> {
  constructor(props, context) {
    super(props, context);
    this.state = {
      dataGoToExcel: '',
      dataGoToExcel2: '',
    };
  }
    handleChange = (event) => {
        this.setState({
          dataGoToExcel: event.target.value,
        })
    };
    handleChange2 = (event) => {
        this.setState({
          dataGoToExcel2: event.target.value,
        })
    };
render(){
    return(
    <div>
      <TextField 
        label="TextField"
        type="text"
        value={this.state.dataGoToExcel}
        onChange={this.handleChange}
      />
      <TextField 
        label="Another TextField"
        type="text"
        value={this.state.dataGoToExcel2}
        onChange={this.handleChange2}
      />
    </div>
      );
   }
  };

编辑:

Parent

import * as React from "react";
import { Dropdown, DropdownMenuItemType, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
import { PrimaryButton } from 'office-ui-fabric-react/lib/';
import Form1 from './Form1';
//import Form2 from './Form2';
export interface ParentProps {

};

export interface ParentState  {
  selectedItem?: { key: string | number | undefined };
  operationType?;
  formName?;
  formData;
  updateFormData?;
};

export default class ParentComponent extends React.Component<ParentProps, ParentState> {
  constructor(props, context) {
    super(props, context);
    this.state = {
      operationType: '',
      formName: '',
      formData: ''
    };
  }

  updateFormData = (data) => this.setState({ formData: data })

  addToExcel = async () => {
    try {
      await Excel.run(async context => {
        const range = context.workbook.getSelectedRange();
        range.load("address");
        await context.sync();
      console.log((`The range address was ${this.state.formData}.`))
      });
    } catch (error) {
      console.error(error);
    }
    this.setState({
      operationType: '',
      formData: '',
      formName: '',
    })
  };
  render() {
    const { selectedItem } = this.state;
    const options: IDropdownOption[] = [
      { key: 'blank', text: '' },
      { key: 'topLevelMake', text: 'Parents', itemType: DropdownMenuItemType.Header },
      { key: 'topLevel', text: 'TOP LEVEL' },
      { key: 'make', text: 'MAKE ITEM' },
    ];
    return (
      <div>
        <Dropdown
          label="Operation"
          selectedKey={selectedItem ? selectedItem.key : undefined}
          onChange={this._onChange}
          placeholder={"Select an option"}
          options={options}
          styles={{ dropdown: { width: 300 } }}
        />
        {this.state.formName}
        <p></p>
        <PrimaryButton
          text="Enter"
          onClick={this.addToExcel}
        />
      </div>
    );
  }
  private _onChange = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption): void => {
    this.setState({ selectedItem: item });
    this.setState({ operationType: item.text })
    console.log(event);
    let Form = <div />;
    switch (item.text) {

      case "TOP LEVEL":
        Form = <Form1 formData={this.state.formData} onDataChange={this.updateFormData} />;
        this.setState({ formName: Form });
        break;

      //case "MAKE ITEM":
      //  Form = <Form2 formData={this.state.formName} onDataChange={this.updateFormData} />;
      //  this.setState({ formName: Form });
      //  break;


      default:
        Form = <div></div>
        break;
    }
  };
}

Form1(注释掉 Form2)

import * as React from "react";
import { TextField } from 'office-ui-fabric-react/lib/';

export interface Form1Props {
  formData: any /* Type of form data */
  onDataChange: (data: any) => void 
};

export default class Form1 extends React.Component<Form1Props> {

  handleChange = (event: any)  => {
    const data = this.props.formData & event.target.value; /* merge props.formdata and event.target.value*/
    this.props.onDataChange(data)
  };

  handleChange2 = (event: any)  => {
    const data = this.props.formData & event.target.value;/* merge props.formdata and event.target.value*/
    this.props.onDataChange(data)
  };

  render(){
    return (
      <div>
        <TextField
          label="TextField"
          type="text"
          value={this.props.formData.dataGoToExcel}
          onChange={this.handleChange}
        />
        <TextField
          label="Another TextField"
          type="text"
          value={this.props.formData.dataGoToExcel2}
          onChange={this.handleChange2}
        />
      </div>
    );
  }
};

一种方法是

  • 具有将表单数据更新为 Parent 状态的功能
  • 将此函数作为 props 传递给 Form 1 和 2。
  • 对于表单中的任何更新,必须调用此函数来更新parent状态
  • 这些更新后的值也必须作为 props 流向 children。

最后,点击Parent中的按钮,就可以提交状态中的内容了。

您必须将局部状态从 Form1 和 Form2 上移到 parent 并将必要的表单值作为 props 发送给 child 组件并且 child 没有局部状态需要组件

编辑:

Parent 组件

export default class ParentComponent extends React.Component<ParentProps, ParentState> {
  constructor(props, context) {
    super(props, context);
    this.state = {
      operationType: '',
      formName: '',
      formData: {/*data as object*/ }
    };
  }

  updateFormData = (data) => this.setState({ formData: data })

  addToExcel = async () => {
    try {
      await Excel.run(async context => {
        const range = context.workbook.getSelectedRange();
        range.load("address");
        await context.sync();
        console.log(`The range address was ${range.address}.`);
      });
    } catch (error) {
      console.error(error);
    }
    this.setState({
      operationType: '',
    })
  };
  render() {
    const { selectedItem } = this.state;
    const options: IDropdownOption[] = [
      { key: 'blank', text: '' },
      { key: 'topLevelMake', text: 'Parents', itemType: DropdownMenuItemType.Header },
      { key: 'topLevel', text: 'TOP LEVEL' },
      { key: 'make', text: 'MAKE ITEM' },
    ];
    return (
      <div>
        <Dropdown
          label="Operation"
          selectedKey={selectedItem ? selectedItem.key : undefined}
          onChange={this._onChange}
          placeholder={"Select an option"}
          options={options}
          styles={{ dropdown: { width: 300 } }}
        />
        {this.state.formName}
        <p></p>
        <PrimaryButton
          text="Enter"
          onClick={this.addToExcel}
        />
      </div>
    );
  }
  private _onChange = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption): void => {
    this.setState({ selectedItem: item });
    this.setState({ operationType: item.text })
    console.log(event);
    let Form = <div />;
    switch (item.text) {

      case "TOP LEVEL":
        Form = <Form1 formData={this.state.formData} onDataChange={this.updateFormData} />;
        this.setState({ formName: Form });
        break;

      case "MAKE ITEM":
        Form = <Form2 formData={this.state.formData} onDataChange={this.updateFormData} />;
        this.setState({ formName: Form });
        break;


      default:
        Form = <div></div>
        break;
    }
  };
}

表单 1 组件

import * as React from "react";
import { TextField } from 'office-ui-fabric-react/lib/';

export interface Form1Props {
  formData: any /* Type of form data */
  onDataChange: (data: any) => void
};

export default class Form1 extends React.Component<Form1Props> {

  handleChange = (event) => {
    const data = /* merge props.formdata and event.target.value*/
    this.props.onDataChange(data)
  };

  handleChange2 = (event) => {
    const data = /* merge props.formdata and event.target.value*/
    this.props.onDataChange(data)
  };

  render(){
    return (
      <div>
        <TextField
          label="TextField"
          type="text"
          value={this.props.formData.dataGoToExcel}
          onChange={this.handleChange}
        />
        <TextField
          label="Another TextField"
          type="text"
          value={this.props.formData.dataGoToExcel2}
          onChange={this.handleChange2}
        />
      </div>
    );
  }
};