Following a click, state change, and render in code
The React documentation features a tic tac toe game as a tutorial that shows some of the features that make React powerful. One such feature is the idea of "state".
We can use state in our tic tac toe game to allow us to move forward and backward in time, jumping to various "moves" that were completed in the past. For example if we're here and we click "Go to move #1"...
It will take us back in time and re-render the board accordingly, putting us here:
Let's follow what happens in the code step by step to see what's happening when "Go to move #1" is clicked:
The onClick for this button is set to
onClick={() => this.jumpTo(move)}>{desc}</button>
So it calls the class method jumpTo and passes in the move number. This move number is simply the index of the map function (in other words, it's the index of the history array that we're in from the map call). More plainly stated, it's the move number that we want to jump to.
Since we just clicked "Go to move #1", it calls this.jumpTo(step), and passes in 1 as the value for step.
jumpTo(1)
Within this jumpTo method we update the state of the Game component. Our full state consists of 3 things:
history
An array of objects where each object contains an array of 9 spaces that represents each square of the board.
stepNumber
A number that indicates which step, or "turn", that we're on.
xIsNext
A boolean that indicates whether or not the next upcoming turn belongs to "X".
But in this call to setState within the jumpTo method, we're only updating stepNumber and xIsNext. This is because we want to keep the history intact (so we can revisit more recent states afterwards).
At this point in time we haven't yet re-rendered the board, but that will come soon now that the stepNumber has been changed from 3 to 1.
No that we've updated our state, our Game component renders again. This is where the board gets updated based on the new stepNumber.
Notice that when we instantiate Board, we pass it a prop called squares which is set current.squares.
current is set by looking at the history array which looks like this:
So it's looking into this history array, at index stepNumber (1), making the value of current an object that looks like this:
{squares: ["X", null, null, null, null, null, null, null, null, null]}
So by the time we get down to the return statement of the render method, where we finally re-render the Board component, we're setting the squares prop to current.squares.
current is the object above, and current.squares is the array at the "squares" key.
So we're setting the squares prop to and array where each slot represents a square on the board. It looks like this:
["X", null, null, null, null, null, null, null, null, null]
What does our Board component do with this array? Let's look inside it find out.
You can see here that we use it in this method called renderSquare where we (you guessed it!) render a Square component.
This renderSquare method takes in one argument: the index of the square, which gets set "by hand" in the nine calls to this.renderSquare() in the return statement.
This index is used to look into the squares array (this.props.squares) to the the "value" of the square (which is used to display an "X", "O", or nothing at all). This value is passed to the square component as the "value" prop.
This how the value of the square button gets set within the Square stateless functional component:
This all takes us from this state:
To this state:
That's it!