Today, we're going to build an interactive tic-tac-toe game.
If you like, you can check out the final result here: <ahref="https://codepen.io/gaearon/pen/VbvBWg?editors=0010"target="_blank">Final Result</a>. Try playing the game. You can also click on a link in the move list to go "back in time" and see what the board looked like just after that move was made.
## Prerequisites
### Prerequisites
We'll assume some familiarity with HTML and JavaScript but you should be able to follow along even if you haven't used them before.
If you need a refresher on JavaScript, we recommend reading [this guide](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript). Note that we're also using some features from ES6, a recent version of JavaScript. In this tutorial, we're using [arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions), [classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes), [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let), and [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const) statements. You can use <ahref="http://babeljs.io/repl/#?babili=false&evaluate=true&lineWrap=false&presets=es2015%2Creact&experimental=false&loose=false&spec=false&code=const%20element%20%3D%20%3Ch1%3EHello%2C%20world!%3C%2Fh1%3E%3B%0Aconst%20container%20%3D%20document.getElementById('root')%3B%0AReactDOM.render(element%2C%20container)%3B%0A">Babel REPL</a> to check what ES6 code compiles to.
## How to Follow Along
### How to Follow Along
### Following Along in Browser
#### Following Along in Browser
We'll be using an online editor called CodePen in this guide. You can begin by opening this <ahref="https://codepen.io/gaearon/pen/JNYBEZ?editors=0010"target="_blank">starter code</a>. It should display an empty tic-tac-toe field. We will be editing that code during this tutorial.
### Following Along Locally
#### Following Along Locally
You can also follow along locally if you don't mind a few extra steps:
@ -48,7 +50,7 @@ You can also follow along locally if you don't mind a few extra steps:
Now if you run `npm start` in the project folder and open `http://localhost:3000` in the browser, you should see an empty tic-tac-toe field.
## Help, I'm Stuck!
### Help, I'm Stuck!
If you get stuck, check out the [community support resources](https://facebook.github.io/react/community/support.html). In particular, [Reactiflux chat](/react/community/support.html#reactiflux-chat) is a great way to get quick help. If you don't get a good answer anywhere, please file an issue, and we'll help you out.
@ -56,7 +58,9 @@ You can also look at the <a href="https://codepen.io/gaearon/pen/VbvBWg?editors=
With this out of the way, let's get started!
## What is React?
## Overview
### What is React?
React is a declarative, efficient, and flexible JavaScript library for building user interfaces.
@ -98,7 +102,7 @@ You can put any JavaScript expression within braces inside JSX. Each React eleme
The `ShoppingList` component only renders built-in DOM components, but you can compose custom React components just as easily, by writing `<ShoppingList />`. Each component is encapsulated so it can operate independently, which allows you to build complex UIs out of simple components.
## Getting Started
### Getting Started
Start with this example: <ahref="https://codepen.io/gaearon/pen/JNYBEZ?editors=0010"target="_blank">Starter Code</a>.
@ -114,7 +118,7 @@ The Square component renders a single `<button>`, the Board renders 9 squares, a
(The end of the JS file also defines a helper function `calculateWinner` that we'll use later.)
## Passing Data Through Props
### Passing Data Through Props
Just to get our feet wet, let's try passing some data from the Board component to the Square component. In Board's `renderSquare` method, change the code to return `<Square value={i} />` then change Square's render method to show that value by replacing `{/* TODO */}` with `{this.props.value}`.
@ -126,7 +130,7 @@ After: You should see a number in each square in the rendered output.
Let's make the Square component fill in an "X" when you click it. Try changing the button tag returned in the `render()` function of the `Square` class to:
@ -166,7 +170,7 @@ Whenever `this.setState` is called, an update to the component is scheduled, cau
If you click on any square, an X should show up in it.
## Developer Tools
### Developer Tools
The React Devtools extension for [Chrome](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) and [Firefox](https://addons.mozilla.org/en-US/firefox/addon/react-devtools/) lets you inspect a React component tree in your browser devtools.
@ -257,7 +261,7 @@ Now you should be able to click in squares to fill them again, but the state is
Square no longer keeps its own state; it receives its value from its parent `Board` and informs its parent when it's clicked. We call components like this **controlled components**.
## Why Immutability Is Important
### Why Immutability Is Important
In the previous code example, we suggest using the `.slice()` operator to copy the `squares` array prior to making changes and to prevent mutating the existing array. Let's talk about what this means and why it is an important concept to learn.
@ -289,13 +293,13 @@ Determining if a mutated object has changed is complex because changes are made
Determining how an immutable object has changed is considerably easier. If the object being referenced is different from before, then the object has changed. That's it.
### Determining When To Re-render in React
#### Determining When To Re-render in React
The biggest benefit of immutability in React comes when you build simple _pure components_. Since immutable data can more easily determine if changes have been made it also helps to determine when a component requires being re-rendered.
To learn how you can build *pure components* take a look at [shouldComponentUpdate()](https://facebook.github.io/react/docs/update.html). Also, take a look at the [Immutable.js](https://facebook.github.io/immutable-js/) library to strictly enforce immutable data.
## Functional Components
### Functional Components
Back to our project, you can now delete the `constructor` from `Square`; we won't need it any more. In fact, React supports a simpler syntax called **stateless functional components** for component types like Square that only consist of a `render` method. Rather than define a class extending React.Component, simply write a function that takes props and returns what should be rendered:
@ -311,7 +315,7 @@ function Square(props) {
You'll need to change `this.props` to `props` both times it appears. Many components in your apps will be able to be written as functional components: these components tend to be easier to write and React will optimize them more in the future.
## Taking Turns
### Taking Turns
An obvious defect in our game is that only X can play. Let's fix that.
@ -349,7 +353,7 @@ render() {
// ...
```
## Declaring a Winner
### Declaring a Winner
Let's show when the game is won. A `calculateWinner(squares)` helper function that takes the list of 9 values has been provided for you at the bottom of the file. You can call it in Board's `render` function to check if anyone has won the game and make the status text show "Winner: [X/O]" when someone wins:
@ -475,7 +479,7 @@ handleClick(i) {
At this point, Board only needs `renderSquare` and `render`; the state initialization and click handler should both live in Game.
## Showing the Moves
### Showing the Moves
Let's show the previous moves made in the game so far. We learned earlier that React elements are first-class JS objects and we can store them or pass them around. To render multiple items in React, we pass an array of React elements. The most common way to build that array is to map over your array of data. Let's do that in the `render` method of Game:
@ -503,7 +507,7 @@ For each step in the history, we create a list item `<li>` with a link `<a>` ins
Let's talk about what that warning means.
## Keys
### Keys
When you render a list of items, React always stores some info about each item in the list. If you render a component that has state, that state needs to be stored – and regardless of how you implement your components, React stores a reference to the backing native views.
@ -540,7 +544,7 @@ If you don't specify any key, React will warn you and fall back to using the arr
Component keys don't need to be globally unique, only unique relative to the immediate siblings.
## Implementing Time Travel
### Implementing Time Travel
For our move list, we already have a unique ID for each step: the number of the move when it happened. Add the key as `<li key={move}>` and the key warning should disappear.
@ -565,7 +569,7 @@ const current = history[this.state.stepNumber];
If you click any move link now, the board should immediately update to show what the game looked like at that time. You may also want to update `handleClick` to be aware of `stepNumber` when reading the current board state so that you can go back in time then click in the board to create a new entry. (Hint: It's easiest to `.slice()` off the extra elements from `history` at the very top of `handleClick`.)