Getting Started with React
Introduction
The golden source of all information on react can be found at https://reactjs.org/.
There is an illuminating tutorial which guides you through building a Tic Tac Toe front end. It is generally well presented with good explanations and I would recommend anyone getting started with React to get started here: https://reactjs.org/tutorial/tutorial.html#data-change-without-mutation The code, which is referenced throughout this post, can be seen here: https://codepen.io/gaearon/pen/gWWZgR?editors=0010
Overview - What can React do for you?
React allows an HTML page to be generated programmatically using OO techniques.
Installation
Install React
npm install -g create-react-app
Create a skeleton app in folder < my-app> with a package.json file which will include all dependencies - in particular react and react-dom
create-react-app <my-app>
Basic idea
At the top of any React js file include react and react-dom:
import React from 'react';
import ReactDOM from 'react-dom';
At the bottom add this:
ReactDOM.render(
<yourReactClass />,
document.getElementById('idOfSomeTagOnSomePage')
);
which will add the html created by your code to a container on a page.
In between add your code which will, hopefully in a pleasant OO manner with TDD, programatically create your page.
Anatomy of Tic Tac Toe in React from the reactjs.org tutorial
see https://codepen.io/gaearon/pen/gWWZgR?editors=0010
Start at the bottom
Starting at the bottom of this file (see below) ReactDOM.render attaches the result of the Game class to the element identified by 'root'
ReactDOM.render(
<Game />,
document.getElementById('root')
);
The < class /> notation, seen above with the Game class, causes the specified class to be executed so long as it inherits from React.Component - components let you split the UI into independent, reusable pieces, and think about each piece in isolation.
The Game Class
Looking at the Game class, which extends React.Component, it looks pretty much like html except in the build it shows the results of the board class via < Board />
The Board Class
The Board class, which extends React.Component, has responsibility for rendering the Tic Tac Toe grid and handling any click in the grid.
It has a constructor method which immediately runs the constructor from the parent class - see super(props) (Why? See questions). It then initialises it's own state with an array called squares and a variable xIsNext which keeps track of whether a nought or cross is next.
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
xIsNext: true,
};
}
The handleclick method defines the response to a click in any of the squares of the grid. It makes use of method calculateWinner, which is a static helper method, to and xIsNext which was initialised in the constructor.
Assuming the game isn't over, state is maintained for squares and xIsNext.
handleClick(i) {
const squares = this.state.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
The renderSquare method sets the value of a square and defines the click event handler as handleClick
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>
);
}
The render method determines the game's status, if there has been a winner (using calculateWinner) or whose turn it is, and renders the status and each individual square.
render() {
const winner = calculateWinner(this.state.squares);
let status;
if (winner) {
status = 'Winner: ' + winner;
} else {
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
Outstanding questions
- Not covered here but how to hook up the React front end with Node/Express backend?
- How to use TDD with React? (Chai?/Mocha?/Enzyme?/Jest?)
- How exactly is index.js hooked up to index.html?
- Why does the Board constructor call the constructor from the parent class
index.js from the reactjs.org tutorial
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
function Square(props) {
return (
<button className="square" onClick={props.onClick}>
{props.value}
</button>
);
}
class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
squares: Array(9).fill(null),
xIsNext: true,
};
}
handleClick(i) {
const squares = this.state.squares.slice();
if (calculateWinner(squares) || squares[i]) {
return;
}
squares[i] = this.state.xIsNext ? 'X' : 'O';
this.setState({
squares: squares,
xIsNext: !this.state.xIsNext,
});
}
renderSquare(i) {
return (
<Square
value={this.state.squares[i]}
onClick={() => this.handleClick(i)}
/>
);
}
render() {
const winner = calculateWinner(this.state.squares);
let status;
if (winner) {
status = 'Winner: ' + winner;
} else {
status = 'Next player: ' + (this.state.xIsNext ? 'X' : 'O');
}
return (
<div>
<div className="status">{status}</div>
<div className="board-row">
{this.renderSquare(0)}
{this.renderSquare(1)}
{this.renderSquare(2)}
</div>
<div className="board-row">
{this.renderSquare(3)}
{this.renderSquare(4)}
{this.renderSquare(5)}
</div>
<div className="board-row">
{this.renderSquare(6)}
{this.renderSquare(7)}
{this.renderSquare(8)}
</div>
</div>
);
}
}
class Game extends React.Component {
render() {
return (
<div className="game">
<div className="game-board">
<Board />
</div>
<div className="game-info">
</div>
</div>
);
}
}
function calculateWinner(squares) {
const lines = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8],
[0, 3, 6],
[1, 4, 7],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6],
];
for (let i = 0; i < lines.length; i++) {
const [a, b, c] = lines[i];
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
return squares[a];
}
}
return null;
}
// ========================================
ReactDOM.render(
<Game />,
document.getElementById('root')
);