Замените родительское состояние на состояние ребенка. Кнопка в родительском - PullRequest
1 голос
/ 06 апреля 2020

РЕДАКТИРОВАТЬ: См. Комментарий Oo для объяснения ответа и варианта в случае, если вы используете классы.

Я столкнулся с чем-то, и я не могу найти решение.

В моем веб-приложении есть 4 компонента:

Parent
   child_1
   child_2
   child_3

У меня есть кнопка на Parent и различные формы (со входами, флажками и радиокнопки) у детей.

У каждого ребенка есть своя собственная кнопка, которая выполняет несколько функций, выполняет некоторые вычисления и обновляет соответствующие состояния. (Никакие состояния не передаются через родителя и потомка).

Мне нужно заменить три кнопки дочерних элементов родительской кнопкой. Есть ли способ, которым я могу выполнить функции в трех дочерних элементов от родительской кнопки и получить результаты? (результаты - один state:value на ребенка.)

Ответы [ 2 ]

0 голосов
/ 06 апреля 2020

Попробуйте выполнить следующее:

  • создайте ссылки, используя useRef для дочерних компонентов формы.
  • для функциональных компонентов, для того чтобы родитель мог получить доступ к дочерним методам, вам нужно чтобы использовать forwardRef
  • с помощью ссылки, вызовите функции дочернего компонента по нажатию родительской кнопки отправки (используя ref.current.methodName)

См. пример кода. Я проверил его на своем локальном компьютере, он работает нормально.

Родитель

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);

Также рекомендуется использовать как можно больше для поддержки состояния и функций в родительском компоненте и передавать необходимые значения / методы дочернему элементу в качестве подпорки.

0 голосов
/ 06 апреля 2020
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>
  );
}

Я не проверял это, но надеюсь, что это поможет вам. И позвольте мне знать, если есть проблема.

...