javascript - Where does passed arguments saved in a rendered react component
问题描述
I was following some tutorials on react web-site and tried some example code included. Here's the link for that code in codepen
https://codepen.io/gaearon/pen/gWWZgR?editors=0010
Here are some snippets to the problem
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
This will call the renderSquare method passing a number as an argument so this will be helpful for identifying onClick method depending on the square (Which is a button).
Here's the renderSquare method
renderSquare(i) {
console.log(<Square/>);
return (
<Square
value={this.props.squares[i]}
onClick={() => this.props.onClick(i)}
/>
);
}
and this method calls a functional component Square,
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
So when a square is clicked it will calls to handleClick(i) method (Better to see codepen link so you'll understand the whole code)
handleClick(i) {
console.log(i);
const history = this.state.history.slice(0, this.state.stepNumber + 1);
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,
}]),
stepNumber: history.length,
xIsNext: !this.state.xIsNext,
});
}
So by using that console.log (Not in codepen code), when I click a button (tic-tac-toe game, so 9 buttons) it will shows the argument which is passed (0,1,2...8).
So my question is where these numbers are stored in those rendered react components? I tried console logging Square component but I couldn't find that argument. (This is not related to props or state)
解决方案
So my question is where these numbers are stored in those rendered react components?
This has nothing to with React. It's how functions work in JavaScript.
Whenever a function is a called, a new environment is created. An environment is an internal data structure to keep state (not to be confused with React component state!). The values of parameters and variables are stored in that environment.
For example consider the function:
function foo(bar) {
var baz = 42;
}
foo(21);
When foo
is called, a new environment is created with the two entries:
<foo environment>
bar: 21
baz: 42
Note: Function calls are isolated. Every time a function is called, a new environment is created just for this call.
In your code
Every time renderSquare
is called, a new environment is created with an entry i
.
Closures are functions which can resolve variables that are not defined in itself. Consider the following example:
function add(x) {
return function innerAdd(y) {
return x + y;
}
}
var add5 = add(5);
add5(2); // 7
Here, innerAdd
references x
, but x
is not defined inside itself, it'
s defined "further up" in add
instead.
When add
is executed, a new environment is created with
<add environment>
x: 5
innerAdd
has a reference to that environment! So when add5
/innerAdd
is executed, it can look up x
in that environment. You can think of the environments being linked together:
<innerAdd environment>
y: 2
parentEnvironment:
<add environment>
x: 5
First we see whether x
is defined in <innerAdd environment>
. Since it is not, we look at its parent, etc.
In your code
Exactly the same happens with the event handler that you are creating inside renderSquare
. The event handler is a function that is created inside an environment where i=0
(and/or i=1
, i=2
, etc).
Here is a simplified example that doesn't use React:
function createButton(i) {
const button = document.createElement('button');
button.textContent = 'Click me';
button.onclick = () => console.log(i);
document.body.appendChild(button);
}
createButton(0);
createButton(1);
createButton(2);
Chrome lets you inspect the environmen(s) associated with a function. For example:
Those shows that the event handler was created inside createButton
where i
has the value 0
.
See also How do JavaScript closures work?
推荐阅读
- r - 数据框之间的子集
- python - 如何在一个 Django 模型实例中存储两个整数?
- javascript - 从子无状态类组件访问来自父无状态功能组件的更新道具
- cmake - 将重复的 CmakeLists.txt 功能移动到公共文件
- wpf - 非常频繁地显示数据时的性能问题
- xml - omnet++解析xml文件
- encryption - 使用第三方工具混淆单个 Java 类文件
- javascript - React Native - 显示来自 API 的数据
- reactjs - 找不到“表单”属性 this.props.form 反应
- php - Laravel:如何在 View Composer 中处理异常