0
votes

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)

3

3 Answers

1
votes

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?

0
votes

in the handleClick method, log out history and you'll see the data is saved in state, in this case this.state.history. try this:

handleClick(i) {
    const history = this.state.history.slice(0, this.state.stepNumber + 1);
    const current = history[history.length - 1];
    console.log('history:', history)
0
votes

They are stored in the state, also the onclick is a function that has the index already:

() => this.props.onClick(i)// line 16 in your code

i is the index you gave and it gets to remain in that function as part of that function. Functions are context aware so when you create a function(closure) in one context it inherits the context it was created in. As such that i will permanently be there for that function even if it was defined outside the closure.

Also the point of the exercise is to show you how to manage state change and how to store it, which is done in the code not some automagic react thing. Whenever an action is done the entire state (which includes that index) is stored to the history.