[英]How is an argument for a callback in React being passed from the child component to the parent component?
I have been working through the React tutorial at https://reactjs.org/tutorial/tutorial.html and I am getting through it well enough. 我一直在使用https://reactjs.org/tutorial/tutorial.html上的React教程,我正在通过它。 I have one thing that I haven't been able to wrap my head around though. 我有一件事我无法绕过头脑。 Here is the code in full (codepen: https://codepen.io/gaearon/pen/EmmOqJ?editors=0010 ): 这是完整的代码(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')
);
In the tutorial they pass a callback function handleClick(i)
from the parent Game
component to the child Board
component and from there to the child Square
component. 在本教程中,他们将回调函数handleClick(i)
从父Game
组件传递到子Board
组件,并从那里传递给子Square
组件。 My question is on how is the argument i
set? 我的问题是如何为参数i
设置? My guess is that the starting point is when renderSquare(i)
is called in the Board
component. 我的猜测是起点是在Board
组件中调用renderSquare(i)
时候。 From there I am lost as to how i
it makes its way to handleClick(i)
. 从那里我迷失了i
如何处理handleClick(i)
。 Is it stored in the 'onClick function object passed to
Square from
Board`? 它存储在'onClick function object passed to
Square from
Board`中吗?
My guess is that the starting point is when renderSquare(i) is called in the Board component. 我的猜测是起点是在Board组件中调用renderSquare(i)的时候。 From there I am lost as to how i it makes its way to handleClick(i) 从那里我迷失了我如何处理点击(i)
You are on the right track. 你走在正确的轨道上。
Within Board.render()
, this.renderSquare(...)
is called with a number 1~8
. 在Board.render()
,使用数字1~8
调用this.renderSquare(...)
。
And renderSquare
has an onClick
handler, this.props.onClick(i)
. renderSquare
有一个onClick
处理程序, this.props.onClick(i)
。
renderSquare(i) {
return (
<Square value={this.props.squares[i]} onClick={() => this.props.onClick(i)}/>
);
}
this.props
is passed from the parent, Game.render()
. this.props
从父, Game.render()
传递。
So this.props.onClick
is from <Board onClick={...} />
所以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>
);
}
}
So this.props.onClick
matches the <Board onClick={...} />
所以this.props.onClick
匹配<Board onClick={...} />
where it's implemented as (i) => this.handleClick(i)
, in which this.handleClick(i)
refers to Game.handleClick(i)
. 它被实现为(i) => this.handleClick(i)
,其中this.handleClick(i)
指的是Game.handleClick(i)
。
Your guessings were good ! 你的猜测很好! I tried to comment the key aspects of the code on this gist : https://gist.github.com/Sangrene/d6784a855e0e3324e5b499e3a5242c45 我试图在这个要点上评论代码的关键方面: https : //gist.github.com/Sangrene/d6784a855e0e3324e5b499e3a5242c45
You are correct in your understanding of the flow and origin of the onClick
function, it is defined in the higher level component Game. 您对onClick
函数的流程和原点的理解是正确的,它在更高级别的组件Game中定义。
The Game
component defines the method onClick
that can be invoked to handle something. Game
组件定义了onClick
方法,可以调用它来处理某些事情。
In reverse order, 以相反的顺序,
The HTML component [ button
] gives a promise to say, if you give me a callback function that matches a said signature, I will call it whenever something happens ( clicked in this event ). HTML组件[ button
]给出了一个承诺,如果你给我一个与所述签名匹配的回调函数,我会在发生某些事情时调用它( 在此事件中单击 )。
Now a higher component (parent to button) to the button Square
function, is both interested in 现在更高的组件(按钮的父级)到按钮Square
功能,都是感兴趣的
But because the Square function itself has no real use case for this event, it decided to delegate the handling of that event to its parent same way as the button did. 但是因为Square函数本身没有这个事件的真实用例,所以它决定将该事件的处理委托给它的父进程与按钮一样。
But it goes a step further to say, if you are interested in receiving this notification, my contract is further extended to say, I will only allow notification of the event if and only if you pass in your callback through a member of my input object as onClick
. 但更进一步说,如果你有兴趣收到这个通知,我的合同会进一步延伸说,我只会允许通知事件当且仅当你通过我的输入对象的成员传递你的回调如onClick
。
So another higher level component Board
(parent to Square) will somehow need to satisfy component Square
requirements of passing in an object with a member onClick
. 因此,另一个更高级别的组件Board
(Square的父级)将以某种方式需要满足传递具有成员onClick
的对象的组件Square
要求。 Notice some things though, the renderSquare
method member of Board
, 注意一些事情, Board
的renderSquare
方法成员,
onClick
properties when initiating a new instance of Square
, and subsequently returning that instance (because JS supports Higher Order Functions Higher Order Functions ) 接收作为输入参数'i',它用于评估某些东西(...)在启动Square
的新实例时设置值和onClick
属性,然后返回该实例(因为JS支持高阶函数高阶函数 ) It defines an anonymous function
as a delegate, of which it's implementation is just to return a member of the props called onClick
( it will appear that the Board also had a contract with any potential parent that there must be a member onClick that's passed on to it )...please note that since this syntax is not yet officially adopted, babel is used to transpile these code into something that a typical browser will understand. 它将anonymous function
定义为委托,其实现只是返回名为onClick
的道具成员( 看起来董事会还与任何潜在的父母签订了合同,必须有一个成员onClick传递给它 )...请注意,因为这句法尚未正式通过,巴别塔是用来transpile这些代码到的东西,一个典型的浏览器就明白了。
renderSquare
method and or Board itself is not doing anything to the onClick member that's been passed around except just returning it in its own anonymous function on onClick={() => this.props.onClick(i)}
renderSquare
方法和或者本身没有对传递的onClick成员做任何事情,只是在onClick={() => this.props.onClick(i)}
中将其返回到自己的匿名函数中
I assume you know how the result of that statement will look, but for argument's sake it basically becomes function onClick(){return [this].props.onClick(i);}
我假设您知道该语句的结果将如何显示,但为了参数,它基本上成为function onClick(){return [this].props.onClick(i);}
Game
( Board
parent), is the one that defines and provides the actual implementation that satisfies the requirements of the onClick
( as defined by button component ) method and passes it on as props
to the child component Board
. 根组件Game
( Board
parent)是定义并提供满足onClick
( 由按钮组件定义 )方法的要求并将其作为props
传递给子组件Board
的实际实现的组件。 Now it means whenever Board
has an encounter with the onClick
specifically from its props
, it will essentially be accessing the anonymous function defined in Game
which subsequently returns Game
's handleClick
function see point 3.2 above. 现在它意味着每当Board
特别从其props
遇到onClick
,它实际上将访问Game
中定义的匿名函数,该函数随后返回Game
的handleClick
函数,参见上面的3.2点。 To attempt to answer your question 试图回答你的问题
My question is on how is the argument i set? 我的问题是我如何设定论点? My guess is that the starting point is when renderSquare(i) is called in the Board component. 我的猜测是起点是在Board组件中调用renderSquare(i)的时候。 From there I am lost as to how i it makes its way to handleClick(i). 从那里我迷失了我如何处理clickClick(i)。 Is it stored in the 'onClick function object passed toSquarefromBoard`? 它存储在'onClick函数对象传递给SquarefromBoard`中吗?
The most important thing to notice here is that, all of this code higher up is all blueprint or definitions on how the code will work when active or invoked, think of it a just a pipeline. 这里要注意的最重要的事情是,所有这些代码更高的是关于代码在活动或调用时如何工作的所有蓝图或定义,将其视为一个管道。 So the definition does not mean that the handleClick(i)
is being called right away, infact it is not called up until later when our button component fires the event, when something causes / satisfied button to publish the event, of which when it happens, the reverse of these steps I've just tried to explain happens all the way down until the root Game's handleClick
function gets invoked. 所以定义并不意味着handleClick(i)
被立即调用,事实上直到我们的按钮组件触发事件时才会调用它,当某些事情导致/满足按钮发布事件时,当事件发生时,我刚刚尝试解释的这些步骤的反向发生,直到根游戏的handleClick
函数被调用。
I realize that my answer could be very long but I hope it paints a message and hopefully helps you to sort of visualize the flow of things. 我意识到我的答案可能很长,但我希望它能描绘出一条信息,并希望能帮助你形象化事物的流动。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.