首页 > 解决方案 > 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)

标签: javascriptreactjsecmascript-6

解决方案


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:

enter image description here

Those shows that the event handler was created inside createButton where i has the value 0.

See also How do JavaScript closures work?


推荐阅读