React for JavaScript programmers II: where to keep the state and why

We were discussing how "regular" JavaScript programmers should learn react. We had discussed functional programming, and how they apply to React. Now, we will discuss it with a real example. Let's use the official reactjs.org tutorial example, They implemented a tic-tac-toe game.

If you learned to program imperatively, you'd define a grid/board and current player, then drill down to have the grid for the moves, basically created a 3x3 table. Then you'd attach event listeners to each grid, marking the moves...

You'd still do that in React, but you start from the bottom up. Think about the smallest repeating element. That's the individual square in the grid/board. Nine of them would be contained by the board. Then the game would contain the board and some verbiage like "Next Player: X" where X will be replaced by either your name or "AI".

So from the top down, the organization is very similar:

Game --> Board --> Square

React, however, starts with the square, which is a bottoms-up approach.

Following the tutorial along, you can see that in the "Making an Interactive Component" step, they made the component accept an onClick event handler. And this modifies the "state" of that square with setState.

onClick={() => this.setState({value: 'X'})}

But this is just an intermediate step in the tutorial. Remember, we need to evaluate the whole board at once to determine the right move and we can't query every square each and every time we want to check the board. That'd be ridiculous. This is where React recommends "lifting state up", and start keeping the overall state in the board component, rather than the lower "square" component. Instead of 9 separate squares storing individual states (null, 'X', 'O'), it should be a single array of 9 entries, one level higher, each with 3 possible values.

What the React tutorial did not discuss is the possibility of using third-party state storage such as Redux. For this simple example, self-storage will do quite nicely. But in a larger project, one may need to consider the possibility of using Redux to store the state. But let us skip that for now.

Anyway, React say we should keep the state in Board component instead, and pass them into square as needed (thus, lifting the state UP from square to board). And every time we need to display something, we render that square with the value passed DOWN from Board. The ONLY source of the state is kept inside the Board component. This is "single source of truth" at work. In fact, the onClick handler at the Square component level can also be passed down from its parent, the board component.

Square components are 'controlled components'. They are controlled by their parent, the Board component.

In fact, Square component is so simple now, it can be converted into a function component... It doesn't even need render() anymore. It is just a return 

SIDENOTE: Do keep in mind that a function component cannot have a state (at least, not directly, but with React hooks, things did change a bit), which is why NOT everything can be function components.

But consider the organization now... the squares are functional components, controlled by board. And board in turn is controlled by app/game, which keeps score, current player, win/lose determination, and so on.

And this makes sense logically. Should we need to create a different game, say, chess, the square component is reusable. (While it'd be trivial to copy a few lines of code, imagine a project where a component contains dozens, hundreds, or even more lines of code, that you can reuse.)

What's more, setState can easily be debugged by tracking all the setState calls, as those would be the only place state was changed.

Remember, state is not a single bit of data, but ALL the data kept by the component, or app. And you can easily add stuff to state by spread and currying.

Coming up next... Spread, currying, and what does context, React Hooks, and all these new stuff have to do with everything.

Comments

Popular posts from this blog

Yet another take on recursion

The Bare Essential Guide to Git

How to Solve a Problem 5: Horse-Racing Duals and HyperDuals