Skip to content

Commit 3f326a5

Browse files
chantastickentcdodds
authored andcommitted
migrate: exercise 04 to kcd-workshop format
1 parent e6070df commit 3f326a5

File tree

30 files changed

+485
-247
lines changed

30 files changed

+485
-247
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Real World Review: Tic Tac Toe
2+
3+
We're going to build tic-tac-toe (with localStorage support)! If you've gone
4+
through React's official tutorial, this was lifted from that.
5+
6+
You're going to need some managed state and some derived state. Remember from
7+
exercise 1:
8+
9+
- **Managed State:** State that you need to explicitly manage
10+
- **Derived State:** State that you can calculate based on other state
11+
12+
`squares` is the managed state and it's the state of the board in a
13+
single-dimensional array:
14+
15+
```
16+
[
17+
'X', 'O', 'X',
18+
'X', 'O', 'O',
19+
'X', 'X', 'O'
20+
]
21+
```
22+
23+
This will start out as an empty array because it's the start of the game.
24+
25+
`nextValue` will be either the string `X` or `O` and is derived state which you
26+
can determine based on the value of `squares`. We can determine whose turn it is
27+
based on how many "X" and "O" squares there are. We've written this out for you
28+
in a `calculateNextValue` function in the `tic-tac-toe-utils.tsx` file.
29+
30+
`winner` will be either the string `X` or `O` and is derived state which can
31+
also be determined based on the value of `squares` and we've provided a
32+
`calculateWinner` function you can use to get that value.
33+
34+
If you want to try this exercise on beast mode then you can ignore
35+
`calculateNextValue` and `calculateWinner` and write your own version of those
36+
utilities.
37+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import '/tic-tac-toe.styles.css';

src/exercise/04.tsx renamed to exercises/04.real-world-review-tic-tac-toe/01.problem/index.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
// Real World Review: Tic Tac Toe
2-
// http://localhost:3000/isolated/exercise/04.tsx
3-
41
import * as React from 'react'
2+
import * as ReactDOM from 'react-dom/client'
53
import {
64
calculateStatus,
75
calculateNextValue,
86
calculateWinner,
9-
} from '../tic-tac-toe-utils'
10-
import type {Squares} from '../tic-tac-toe-utils'
7+
} from '~/shared/tic-tac-toe-utils'
8+
import type {Squares} from '~/shared/tic-tac-toe-utils'
119

1210
function Board() {
1311
// 🐨 squares is the state for this component. Add useState for squares
@@ -89,7 +87,9 @@ function App() {
8987
)
9088
}
9189

92-
export {App}
90+
const rootEl = document.createElement('div')
91+
document.body.append(rootEl)
92+
ReactDOM.createRoot(rootEl).render(<App />)
9393

9494
/*
9595
eslint
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Real World Review: Tic Tac Toe
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import '/tic-tac-toe.styles.css';

src/final/04.tsx renamed to exercises/04.real-world-review-tic-tac-toe/01.solution/index.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,11 @@
1-
// Real World Review: Tic Tac Toe
2-
// http://localhost:3000/isolated/final/04.tsx
3-
41
import * as React from 'react'
2+
import * as ReactDOM from 'react-dom/client'
53
import {
64
calculateStatus,
75
calculateNextValue,
86
calculateWinner,
9-
} from '../tic-tac-toe-utils'
10-
import type {Squares} from '../tic-tac-toe-utils'
7+
} from '~/shared/tic-tac-toe-utils'
8+
import type {Squares} from '~/shared/tic-tac-toe-utils'
119

1210
function Board() {
1311
const [squares, setSquares] = React.useState<Squares>(Array(9).fill(null))
@@ -74,4 +72,6 @@ function App() {
7472
)
7573
}
7674

77-
export {App}
75+
const rootEl = document.createElement('div')
76+
document.body.append(rootEl)
77+
ReactDOM.createRoot(rootEl).render(<App />)
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Preserve State in localStorage
2+
3+
👨‍💼 Our customers want to be able to close the tab in the middle of a game and
4+
then resume the game later. Can you store the game's state in `localStorage`?
5+
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
@import '/tic-tac-toe.styles.css';
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import * as React from 'react'
2+
import * as ReactDOM from 'react-dom/client'
3+
import {
4+
calculateStatus,
5+
calculateNextValue,
6+
calculateWinner,
7+
} from '~/shared/tic-tac-toe-utils'
8+
import type {Squares} from '~/shared/tic-tac-toe-utils'
9+
10+
function Board() {
11+
const [squares, setSquares] = React.useState<Squares>(Array(9).fill(null))
12+
13+
const nextValue = calculateNextValue(squares)
14+
const winner = calculateWinner(squares)
15+
const status = calculateStatus(winner, squares, nextValue)
16+
17+
function selectSquare(index: number) {
18+
if (winner || squares[index]) {
19+
return
20+
}
21+
setSquares(previousSquares => {
22+
const squaresCopy = [...previousSquares]
23+
squaresCopy[index] = nextValue
24+
return squaresCopy
25+
})
26+
}
27+
28+
function restart() {
29+
setSquares(Array(9).fill(null))
30+
}
31+
32+
function renderSquare(i: number) {
33+
return (
34+
<button className="square" onClick={() => selectSquare(i)}>
35+
{squares[i]}
36+
</button>
37+
)
38+
}
39+
40+
return (
41+
<div>
42+
<div className="status">{status}</div>
43+
<div className="board-row">
44+
{renderSquare(0)}
45+
{renderSquare(1)}
46+
{renderSquare(2)}
47+
</div>
48+
<div className="board-row">
49+
{renderSquare(3)}
50+
{renderSquare(4)}
51+
{renderSquare(5)}
52+
</div>
53+
<div className="board-row">
54+
{renderSquare(6)}
55+
{renderSquare(7)}
56+
{renderSquare(8)}
57+
</div>
58+
<button className="restart" onClick={restart}>
59+
restart
60+
</button>
61+
</div>
62+
)
63+
}
64+
65+
function App() {
66+
return (
67+
<div className="game">
68+
<div className="game-board">
69+
<Board />
70+
</div>
71+
</div>
72+
)
73+
}
74+
75+
const rootEl = document.createElement('div')
76+
document.body.append(rootEl)
77+
ReactDOM.createRoot(rootEl).render(<App />)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Preserve State in localStorage

0 commit comments

Comments
 (0)