React – 将事件从 child 组件传递到 parent

React – Passing event from child component to parent

我是 React.js 的新手,如果这是一个愚蠢的问题或之前有人问过,我深表歉意。我有一个组件树结构如下: form (grandparent) → input field (parent) → button (child)

我正在尝试监听 按钮 的点击(onClick 事件处理程序),并在 表单 (理想情况下也将输入字段的内容传递给表单)。

是否有执行此操作的通用方法或我应该阅读的文档的特定部分?我知道我可以通过 props 将数据从 parent 传递到 child,这有相反的做法吗?

您可以让表单将函数作为 prop 传递给子项,然后让子项将该函数作为 prop 传递给按钮,如下所示:

const {useState} = React;

const Example = () => {
    const onClick = () => {
        console.log("Clicked!");
    };
    return <Parent onClick={onClick} />;
};

const Parent = ({onClick}) => {
    return <button type="button" onClick={onClick}>Click Me</button>;
};


ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

对于这个简单的例子,我只是在每次渲染 Example 时重新创建函数,但有时你不想这样做,因为它使 Parentbutton 两者 re-render 随时 Example 中的任何内容发生变化。您可以使用 useCallback or useMemo to avoid passing a new function to Parent (and thus to button) every time. (That would only help if Parent and any other intermediate components were memoized, as with React.memo or [for class components] PureComponent or a component using shouldComponentUpdate.) More about that in my other answers and .

这里展示了更改与点击处理程序无关的内容如何导致不必要的 re-rendering Parent:

const { useState, useEffect } = React;

const Example = () => {
    const [counter, setCounter] = useState(0);
    useEffect(() => {
        const handle = setInterval(
            () => setCounter(c => c + 1),
            800
        );
        return () => {
            clearInterval(handle);
        };
    }, []);
    const onClick = () => {
        console.log("Clicked!");
    };
    return <div>
        <div>
            Counter: {counter}
        </div>
        <Parent onClick={onClick} />
    </div>;
};

const Parent = ({onClick}) => {
    console.log(`Parent rendering...`);
    return <button type="button" onClick={onClick}>Click Me</button>;
};


ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

还有一个示例,它记录了 onClick 并使用 React.memo 使 Parent 而不是 re-render 当没有什么重要的(对它)改变时:

const { useState, useEffect, useCallback } = React;

const Example = () => {
    const [counter, setCounter] = useState(0);
    useEffect(() => {
        const handle = setInterval(
            () => setCounter(c => c + 1),
            800
        );
        return () => {
            clearInterval(handle);
        };
    }, []);
    const onClick = useCallback(() => {
        console.log("Clicked!");
    }, []);
    return <div>
        <div>
            Counter: {counter}
        </div>
        <Parent onClick={onClick} />
    </div>;
};

const Parent = React.memo(({onClick}) => {
    console.log(`Parent rendering...`);
    return <button type="button" onClick={onClick}>Click Me</button>;
});


ReactDOM.render(<Example />, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>