简体   繁体   English

用子级的 state 替换父级 state。 父级按钮

[英]Replace parent state with state of child. Button in parent

EDIT: See the comment of Oo for the explanation of the answer and the variant in case you are using classes.编辑:如果您使用类,请参阅 Oo 的评论以了解答案和变体的解释。

I've come across to something and I can't find the solution.我遇到了一些事情,但我找不到解决方案。

I have 4 components in my web app:我的 web 应用程序中有 4 个组件:

Parent
   child_1
   child_2
   child_3

I have a button on the Parent , and different forms (with inputs, checkboxes and radiobuttons) at the children.我在Parent上有一个按钮,在孩子上有不同的 forms (带有输入、复选框和单选按钮)。

Each child has his own button that executes several functions, some calculations, and updates the corresponding states.每个孩子都有自己的按钮,可以执行几个功能、一些计算并更新相应的状态。 (No states are passed through parent and child). (没有状态通过父母和孩子传递)。

I need to replace the three buttons of the children with the parent button.我需要用父按钮替换孩子的三个按钮。 Is there a way that I can execute the functions at the three children from the parent button and retrieve the results?有没有办法可以从父按钮执行三个子项的功能并检索结果? (the results are one state:value per child.) (结果是一个state:value 。)

function Child1(props) {
   const [value, setValue] = useState("");
   useEffect(() => {
      calculate();
   }, [props.flag]);
   calculate() {
       //blah blah
   }
   onChange(e) {
      setValue(e.target.value);
      props.onChange(e.target.value); // update the state in the parent component
   }
   return (
      <input value={value} onChange={(e) => onChange(e)} />
   );
}

function Parent(props) {
  const [flag, setFlag] = useState(false);
  const [child1Value, setChild1Value] = useState("");
  return (
    <div>
       <Child1 flag={flag} onChange={(value) => setChild1Value(value)}/>
       <button onClick={() => setFlag(!flag)} />
    </div>
  );
}

I didn't test this but hope this helps you.我没有对此进行测试,但希望对您有所帮助。 And lemme know if there is an issue.让我知道是否有问题。

Try the following:尝试以下操作:

  • create refs using useRef for child form components.使用useRef为子表单组件创建 refs。
  • for functional components, in order for the parent to access the child's methods, you need to use forwardRef对于功能组件,为了让父级访问子级的方法,需要使用forwardRef
  • using the ref, call child component functions on click of parent submit button (using ref.current.methodName )使用 ref,在单击父提交按钮时调用子组件函数(使用ref.current.methodName

See the example code.请参阅示例代码。 I have tested it on my local, it is working ok.我已经在本地测试过,它工作正常。

Parent家长

import React, { Fragment, useState, useRef } from "react";
import ChildForm1 from "./ChildForm1";

const Parent = props => {
  const [form1Data, setFormData] = useState({});//use your own data structure..
  const child1Ref = useRef();
  // const child2Ref = useRef(); // for 2nd Child Form...

  const submitHandler = e => {
    e.preventDefault();
    // execute childForm1's function
    child1Ref.current.someCalculations();
    // execute childForm2's function

    //    finally do whatever you want with formData
    console.log("form submitted");
  };

  const notifyCalcResult = (calcResult) => {
      // update state based on calcResult
      console.log('calcResult', calcResult);
  };

  const handleChildFormChange = data => {
    setFormData(prev => ({ ...prev, ...data }));
  };

  return (
    <Fragment>
      <h1 className="large text-primary">Parent Child demo</h1>
      <div>
        <ChildForm1
            notifyCalcResult={notifyCalcResult}
            ref={child1Ref}
            handleChange={handleChildFormChange} />
          {/*{do the same for ChildForm2 and so on...}*/}
        <button onClick={submitHandler}>Final Submit</button>
      </div>
    </Fragment>
  );
};

export default Parent;

ChildFormComponent子窗体组件

import React, { useState, useEffect, forwardRef, useImperativeHandle } from "react";

const ChildForm1 = ({ handleChange, notifyCalcResult }, ref) => {
  const [name, setName] = useState("");
  const [calcResult, setCalcResult] = useState([]);

  const someCalculations = () => {
    let result = ["lot_of_data"];
    //  major calculations goes here..
    //  result = doMajorCalc();
    setCalcResult(result);
  };
  useImperativeHandle(ref, () => ({ someCalculations }));

  useEffect(() => {
    //  notifiy parent
    notifyCalcResult(calcResult);
  }, [calcResult]);

  return (
    <form className="form">
      <div className="form-group">
        <input
            value={name}// //TODO: handle this...
          onChange={() => handleChange(name)}//TODO: notify the value back to parent 
          type="text"
          placeholder="Enter Name"
        />
      </div>
    </form>
  );
};

export default forwardRef(ChildForm1);

Also as a best practice, consider to maintain state and functions in the parent component as much as possible and pass the required values/methods to the child as props.同样作为最佳实践,考虑尽可能在父组件中维护 state 和函数,并将所需的值/方法作为道具传递给子组件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM