如何在React中从子组件向父组件发送数据,当父组件中的按钮被点击时?

huangapple go评论56阅读模式
英文:

How to send data from child to parent when a button in Parent is clicked in react?

问题

我知道如何在单击按钮时从子组件向父组件发送数据,但按钮应该在子组件中。
我想要的是,当单击按钮时,如何从子组件向父组件发送数据,但按钮在父组件中而不是子组件中。

举例来说,我有这样的东西:

父组件

function ParentComponent() {
  const handleChildData = (childData) => {
    console.log(childData);
  }
  return (
    <>
      <ChildComponent onDataGet={handleChildData} />
      <div>ParentComponent</div>
    </>
  )
}

子组件

function ChildComponent({onDataGet}) {
  const data = {
    firstName: "John",
    lastName: "Smith",
  }

  // 根据某些条件,执行此函数:
  onDataGet(data)

  return (
    <div>ChildComponent</div>
  )
}

我尝试过这种方法:

定义了一个状态,在每次点击时,状态递增一次,还将此状态传递给子组件,在子组件中,每当状态发生变化时,子组件的 useEffect 将会执行并执行 onDataGet 函数。像这样:

父组件

function ParentComponent() {
  const [isTrigerred, setIsTrigerred] = useState(1);
  const handleChildData = (childData) => {
    console.log(childData);
  };
  return (
    <>
      <ChildComponent onDataGet={handleChildData} gotChanged={isTrigerred} />
      <div>ParentComponent</div>
      <Button variant="contained" onClick={() => setIsTrigerred((prev) => prev + 1)}>
        Click Me
      </Button>
    </>
  );
}

子组件

function ChildComponent({ onDataGet, gotChanged}) {
  const data = {
    firstName: "John",
    lastName: "Smith",
  };

  useEffect(() => {
    // 第一次渲染时不执行
    if (gotChanged !== 1) {
      onDataGet(data);
    }
  }, [gotChanged]);

  return <div>ChildComponent</div>;
}

但我正在寻找一种更好的方法,如果有的话。

谢谢。

英文:

I know how to send data from child to parent component when a button is clicked, but the button should be in child component.
What I want is, how to send data from child to parent when a button is clicked, but the button is in parent component not in child component.

For instance, I have something like this:

Parent component

function ParentComponent() {
  const handleChildData = (childData) =&gt; {
    console.log(childData);
  }
  return (
    &lt;&gt; 
    &lt;ChildComponent onDataGet={handleChildData} /&gt;
    &lt;div&gt;ParentComponent&lt;/div&gt;
    &lt;/&gt;
  )
}

Child component

function ChildComponent({onDataGet}) {
  const data = {
    firstName: &quot;John&quot;,
    lastName: &quot;Smith&quot;,
  }

  // Based on something, execute this function:
  onDataGet(data)

  return (
    &lt;div&gt;ChildComponent&lt;/div&gt;
  )
}

I have tried this approach:

defined a state, on each click the state increments by one, also passed this state to child, in there anytime the state gets changed, useEffect in child component will happen and will execute the onDataGet function. Like this:

Parent Component

function ParentComponent() {
  const [isTrigerred, setIsTrigerred] = useState(1);
  const handleChildData = (childData) =&gt; {
    console.log(childData);
  };
  return (
    &lt;&gt;
      &lt;ChildComponent onDataGet={handleChildData} gotChanged={isTrigerred} /&gt;
      &lt;div&gt;ParentComponent&lt;/div&gt;
      &lt;Button variant=&quot;contained&quot; onClick={() =&gt; setIsTrigerred((prev) =&gt; prev + 1)}&gt;
        Click Me
      &lt;/Button&gt;
    &lt;/&gt;
  );
}

Child Component

function ChildComponent({ onDataGet, gotChanged}) {
  const data = {
    firstName: &quot;John&quot;,
    lastName: &quot;Smith&quot;,
  };

  useEffect(() =&gt; {
    // Don&#39;t execute in first render
    if (gotChanged !== 1) {
      onDataGet(data);
    }
  }, [gotChanged]);

  return &lt;div&gt;ChildComponent&lt;/div&gt;;
}

But I'm looking for a better approach, if there is any.

Thanks.

答案1

得分: 2

以下是您要翻译的内容:

父组件:

function ParentComponent() {
  const [getChildData, setGetChildData] = useState(() => null);

  const handleChildData = () => {
    const childData = getChildData();
    // 等等...
  };
  return (
    <>
      <ChildComponent getDataSetter={setGetChildData} />
      <div>ParentComponent</div>
      <Button variant="contained" onClick={handleChildData}>
        点击我
      </Button>
    </>
  );
}

子组件:

function ChildComponent({ getDataSetter }) {
  const [data, setData] = useState({
    firstName: 'John',
    lastName: 'Smith',
  });

  useEffect(() => {
    // 这是使用函数来设置状态的唯一方法,因为设置函数可以接受回调函数来设置新的值
    getDataSetter(() => () => data);
  }, [data]);

  return <div>ChildComponent</div>;
}
英文:

One approach may be to pass a setter for the wanted function in your child component like this :

Parent Component :

function ParentComponent() {
  const [getChildData, setGetChildData] = useState(() =&gt; null);

  const handleChildData = () =&gt; {
    const childData = getChildData();
    // etc...
  };
  return (
    &lt;&gt;
      &lt;ChildComponent getDataSetter={setGetChildData} /&gt;
      &lt;div&gt;ParentComponent&lt;/div&gt;
      &lt;Button variant=&quot;contained&quot; onClick={handleChildData}&gt;
        Click Me
      &lt;/Button&gt;
    &lt;/&gt;
  );
}

Child Component :

function ChildComponent({ getDataSetter }) {
  const [data, setData] = useState({
    firstName: &#39;John&#39;,
    lastName: &#39;Smith&#39;,
  });

  useEffect(() =&gt; {
    // Only way to use a state for a function, because the setter function
    // can take a callback to set the new value
    getDataSetter(() =&gt; () =&gt; data);
  }, [data]);

  return &lt;div&gt;ChildComponent&lt;/div&gt;;
}

答案2

得分: 2

缓存函数 ref 的功能可用于实现父组件调用子组件的方法。

import {useRef} from 'react'

function ParentComponent() {
  const actionRef = useRef();
  return (
    <>
      <ChildComponent ref={actionRef} />
      <div>ParentComponent</div>
      <Button
        variant="contained"
        onClick={() => {
          const childData = actionRef.current.getData();
          console.log('childData...', childData);
        }}
      >
        Click Me
      </Button>
    </>
  );
}

import {forwardRef} from 'react'

const ChildComponent = forwardRef(function (props, ref) {
  const data = {
    firstName: 'John',
    lastName: 'Smith',
  };

  useImperativeHandle(
    ref,
    () => {
     // 返回的对象将传递给父组件的 ref.current,所以你可以添加任何你想要的内容。
      return {
        getData: () => data,
      }
    },
    [data],
  );

  return <div>ChildComponent</div>;
});
英文:

The caching function of ref can be used to realize the method of parent calling child components.

import {useRef} from &#39;react&#39;

function ParentComponent() {
  const actionRef = useRef();
  return (
    &lt;&gt;
      &lt;ChildComponent ref={actionRef} /&gt;
      &lt;div&gt;ParentComponent&lt;/div&gt;
      &lt;Button
        variant=&quot;contained&quot;
        onClick={() =&gt; {
          const childData = actionRef.current.getData();
          console.log(&#39;childData...&#39;, childData);
        }}
      &gt;
        Click Me
      &lt;/Button&gt;
    &lt;/&gt;
  );
}
import {forwardRef} from &#39;react&#39;

const ChildComponent = forwardRef(function (props, ref) {
  const data = {
    firstName: &#39;John&#39;,
    lastName: &#39;Smith&#39;,
  };

  useImperativeHandle(
    ref,
    () =&gt; {
     // the return object will pass to parent ref.current, so you can add anything what you want.
      return {
        getData: () =&gt; data,
      }
    },
    [data],
  );

  return &lt;div&gt;ChildComponent&lt;/div&gt;;
});

huangapple
  • 本文由 发表于 2023年5月15日 15:46:27
  • 转载请务必保留本文链接:https://go.coder-hub.com/76251892.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定