【问题标题】:How is an argument for a callback in React being passed from the child component to the parent component?React 中的回调参数如何从子组件传递到父组件?
【发布时间】:2019-04-26 13:03:06
【问题描述】:

我一直在学习https://reactjs.org/tutorial/tutorial.html 上的 React 教程,并且已经很好地完成了它。不过,我有一件事我无法理解。这是完整的代码(codepen:https://codepen.io/gaearon/pen/EmmOqJ?editors=0010):

function Square(props) {  
    return (
      <button className="square"
              onClick={props.onClick}>

          {props.value}
      </button>
    );
}

function calculateWinner(squares) {
    const lines = [  
        [0, 1, 2],
        [3, 4, 5],
        [6, 7, 8],
        [0, 3, 6],
        [1, 4, 7],
        [2, 5, 8],
        [0, 4, 8],
        [2, 4, 6],
    ];

    for (let i = 0; i < lines.length; i++) {
        const [a, b, c] = lines[i];

        if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
            return squares[a];
        }
    }

    return null;
}

class Board extends React.Component {
    renderSquare(i) {
        return (
            <Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)}/>  
        );
    }

    render() {  
        return (
            <div>
                <div className="status">{status}</div>
                <div className="board-row">
                    {this.renderSquare(0)}
                    {this.renderSquare(1)}
                    {this.renderSquare(2)}
                </div>
                <div className="board-row">
                    {this.renderSquare(3)}
                    {this.renderSquare(4)}
                    {this.renderSquare(5)}
                </div>
                <div className="board-row">
                    {this.renderSquare(6)}
                    {this.renderSquare(7)}
                    {this.renderSquare(8)}
                </div>
            </div>
        );
    }
}

class Game extends React.Component {
    constructor(props) {
        super(props);  

        this.state = {
            history: [{
                squares: Array(9).fill(null),
            }],
            xIsNext: true,
        };
    }

    handleClick(i) {
        const history = this.state.history;
        const current = history[history.length - 1];
        const squares = current.squares.slice();  

        if (calculateWinner(squares) || squares[i]) {  
            return;
        }

        squares[i] = this.state.xIsNext ? 'X' : 'O';

        this.setState({
            history: history.concat([{
                squares: squares,
            }]),  
            xIsNext: !this.state.xIsNext,
        });  
    }

    render() {
        const history = this.state.history;
        const current = history[history.length - 1];
        const winner = calculateWinner(current.squares);

        let status;

        if (winner) {
            status = 'Winner: ' + winner;
        } else {
            status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
        }

        return (
            <div className="game">
                <div className="game-board">
                    <Board  
                        squares={current.squares}
                        onClick={(i) => this.handleClick(i)}  
                    />
                </div>
                <div className="game-info">
                    <div>{status}</div>
                    <ol>{/* TODO */}</ol>
                </div>
            </div>
        );
    }
}

// ========================================

ReactDOM.render(
  <Game />,
  document.getElementById('root')
);

在教程中,他们将回调函数 handleClick(i) 从父 Game 组件传递给子 Board 组件,然后从那里传递给子 Square 组件。我的问题是论点i 是如何设置的?我的猜测是,起点是在 Board 组件中调用 renderSquare(i) 时。从那里我迷失了i它是如何到达handleClick(i)的。它是否存储在'onClickfunction object passed toSquarefromBoard`中?

【问题讨论】:

  • 我记得在这个完全相同的问题上苦苦挣扎,因为很难找到代码流。
  • @SungKim 您使用哪些资源来了解代码流?感谢您在下方提供帮助?
  • 在多次失败后,我遇到了 Dave Ceddia 的 Pure React。它让你写了很多代码。我就是这样习惯的。

标签: javascript reactjs callback


【解决方案1】:

您对onClick函数的流程和来源的理解是正确的,它是在更高级别的组件游戏中定义的。

Game 组件定义了方法onClick,可以调用该方法来处理某些事情。

以相反的顺序,

  1. HTML 组件 [button] 承诺说,如果你给我一个 与上述签名匹配的回调函数,我将调用它 每当有事情发生时(点击此事件)。

  2. 现在是按钮Square 的更高组件(按钮的父级) 功能,都对

    感兴趣
    • 使用按钮和
    • 有兴趣在事件发生时根据承诺按钮获得通知 第 (1) 点提供。

但是因为 Square 函数本身没有 对于这个事件的真实用例,它决定委托处理 该事件以与按钮相同的方式传递给其父级。

但更进一步说,如果您有兴趣接收此通知,我的合同进一步扩展为,当且仅当您通过成员传递回调时,我才允许通知事件我的输入对象为onClick。

  1. 所以另一个更高级别的组件Board(Square 的父级)将 不知何故需要满足组件Square传入对象的要求 与成员onClick。不过请注意一些事情,Board 的 renderSquare 方法成员,

    • 接收作为输入参数“i”,它用于评估某事 (...) 在启动 Square 的新实例时设置值和 onClick 属性,然后返回该实例(因为 JS 支持更高订购功能Higher Order Functions)
    • 它将anonymous function 定义为一个委托,它的实现只是返回一个名为onClick 的道具成员(看来董事会也有任何潜在的合同parent 必须有一个成员 onClick 传递给它)...请注意,由于此语法尚未正式采用,因此 babel 用于将这些代码转换为典型浏览器可以理解的内容。

    • renderSquare 方法和/或 Board 本身没有对传递的 onClick 成员做任何事情,只是在 onClick={() =&gt; this.props.onClick(i)} 上的自己的匿名函数中返回它

    我假设你知道那个语句的结果会是什么样子,但是为了论证,它基本上变成了 function onClick(){return [this].props.onClick(i);}

    1. 根组件Game(Board parent)是定义并提供满足onClick(由按钮组件定义)方法要求的实际实现的组件并将其作为props 传递给子组件Board。现在这意味着每当Board 遇到onClick 尤其是来自其props 时,它本质上将访问Game 中定义的匿名函数,该函数随后返回Game 的handleClick 函数参见第3.2 点更多。

尝试回答您的问题

我的问题是我如何设置论点?我的猜测是 起点是在 Board 中调用 renderSquare(i) 时 零件。从那里我迷失了它是如何到达的 手柄点击(一)。是否存储在传递的'onClick函数对象中 toSquarefromBoard`?​​

这里要注意的最重要的事情是,所有这些代码都是蓝图或关于代码在活动或调用时如何工作的定义,将其视为一个管道。所以这个定义并不意味着handleClick(i) 会被立即调用,事实上它直到稍后我们的按钮组件触发事件时才会被调用,当某些事情导致/满意按钮发布事件时,当它发生时,我刚刚试图解释的这些步骤的逆向一直发生,直到根游戏的handleClick 函数被调用。

我意识到我的回答可能会很长,但我希望它能传达一个信息,并希望能帮助您将事物的流程形象化。

【讨论】:

    【解决方案2】:

    你的猜测不错!我试图在这个要点上评论代码的关键方面:https://gist.github.com/Sangrene/d6784a855e0e3324e5b499e3a5242c45

    【讨论】:

    • 查看代码旁边的解释很有帮助。在花费大量时间使用 Python 之后,JSX 发生了很大的变化。这里的规则是否要求代码与链接一起发布?
    • 我不这么认为,我看到很多人分享他们的 codepen 或关于 SO 答案的要点 :)
    【解决方案3】:

    我的猜测是起点是在 Board 组件中调用 renderSquare(i) 时。从那里我迷失了它如何处理点击(i)

    你在正确的轨道上。

    在Board.render() 内,this.renderSquare(...) 被调用一个号码1~8。

    而renderSquare 有一个onClick 处理程序this.props.onClick(i)。

    renderSquare(i) {
        return (
            <Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)}/>  
        );
    }
    

    this.props 是从父级传递的,Game.render()。
    所以this.props.onClick来自&lt;Board onClick={...} /&gt;

    class Game extends React.Component {
        handleClick(i) {
           ...
        }
    
        render() {
            ...
            return (
                <div className="game">
                    <div className="game-board">
                        <Board  
                            squares={current.squares}
                            onClick={(i) => this.handleClick(i)}  
                        />
                    </div>
                    ...
                </div>
            );
        }
    }
    

    所以this.props.onClick 匹配&lt;Board onClick={...} /&gt;
    它被实现为(i) =&gt; this.handleClick(i),其中this.handleClick(i)指的是Game.handleClick(i)。

    【讨论】:

      猜你喜欢
      • 2022-06-30
      • 1970-01-01
      • 2019-05-30
      • 1970-01-01
      • 1970-01-01
      • 2020-04-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多