繁体   English   中英

React中的回调参数如何从子组件传递到父组件?

[英]How is an argument for a callback in React being passed from the child component to the parent component?

我一直在使用https://reactjs.org/tutorial/tutorial.html上的React教程,我正在通过它。 我有一件事我无法绕过头脑。 这是完整的代码(codepen: https ://codepen.io/gaearon/pen/EmmOqJ edit = 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) 它存储在'onClick function object passed to Square from Board`中吗?

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

你走在正确的轨道上。

Board.render() ,使用数字1~8调用this.renderSquare(...)

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来自<Board onClick={...} />

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匹配<Board onClick={...} />
它被实现为(i) => this.handleClick(i) ,其中this.handleClick(i)指的是Game.handleClick(i)

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

您对onClick函数的流程和原点的理解是正确的,它在更高级别的组件Game中定义。

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

以相反的顺序,

  1. HTML组件[ button ]给出了一个承诺,如果你给我一个与所述签名匹配的回调函数,我会在发生某些事情时调用它( 在此事件中单击 )。

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

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

但是因为Square函数本身没有这个事件的真实用例,所以它决定将该事件的处理委托给它的父进程与按钮一样。

但更进一步说,如果你有兴趣收到这个通知,我的合同会进一步延伸说,我只会允许通知事件当且仅当你通过我的输入对象的成员传递你的回调如onClick

  1. 因此,另一个更高级别的组件Board (Square的父级)将以某种方式需要满足传递具有成员onClick的对象的组件Square要求。 注意一些事情, BoardrenderSquare方法成员,

    • 接收作为输入参数'i',它用于评估某些东西(...)在启动Square的新实例时设置值和onClick属性,然后返回该实例(因为JS支持高阶函数高阶函数
    • 它将anonymous function定义为委托,其实现只是返回名为onClick的道具成员( 看起来董事会还与任何潜在的父母签订了合同,必须有一个成员onClick传递给它 )...请注意,因为这句法尚未正式通过,巴别塔是用来transpile这些代码到的东西,一个典型的浏览器就明白了。

    • renderSquare方法和或者本身没有对传递的onClick成员做任何事情,只是在onClick={() => this.props.onClick(i)}中将其返回到自己的匿名函数中

    我假设您知道该语句的结果将如何显示,但为了参数,它基本上成为function onClick(){return [this].props.onClick(i);}

    1. 根组件GameBoard parent)是定义并提供满足onClick由按钮组件定义 )方法的要求并将其作为props传递给子组件Board的实际实现的组件。 现在它意味着每当Board特别从其props遇到onClick ,它实际上将访问Game中定义的匿名函数,该函数随后返回GamehandleClick函数,参见上面的3.2点。

试图回答你的问题

我的问题是我如何设定论点? 我的猜测是起点是在Board组件中调用renderSquare(i)的时候。 从那里我迷失了我如何处理clickClick(i)。 它存储在'onClick函数对象传递给SquarefromBoard`中吗?

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

我意识到我的答案可能很长,但我希望它能描绘出一条信息,并希望能帮助你形象化事物的流动。

暂无
暂无

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

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