Skip to content

Commit a71a47a

Browse files
authored
Merge branch 'main' into update-readme
2 parents cc70e7d + 4f64985 commit a71a47a

File tree

2 files changed

+75
-78
lines changed

2 files changed

+75
-78
lines changed

.github/workflows/publish.yml

-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ jobs:
1616
registry-url: 'https://registry.npmjs.org'
1717
cache: 'pnpm'
1818
- run: pnpm install
19-
- run: pnpm test
2019
- run: pnpm build
2120
- run: npm publish
2221
env:

docs/guides/tutorial-tic-tac-toe.md

+75-77
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,10 @@ function Board({ xIsNext, squares, onPlay }) {
123123
}
124124

125125
export default function Game() {
126-
const { history, setHistory, currentMove, setCurrentMove } = useGameStore()
126+
const history = useGameStore((state) => state.history)
127+
const setHistory = useGameStore((state) => state.setHistory)
128+
const currentMove = useGameStore((state) => state.currentMove)
129+
const setCurrentMove = useGameStore((state) => state.setCurrentMove)
127130
const xIsNext = currentMove % 2 === 0
128131
const currentSquares = history[currentMove]
129132

@@ -215,7 +218,7 @@ The `Square` component should take `value` and `onSquareClick` as props. It shou
215218

216219
Here's the code for the `Square` component:
217220

218-
```tsx
221+
```jsx
219222
function Square({ value, onSquareClick }) {
220223
return (
221224
<button
@@ -253,7 +256,7 @@ interactions.
253256

254257
Here's the code for the `Board` component:
255258

256-
```tsx
259+
```jsx
257260
export default function Board() {
258261
return (
259262
<div
@@ -307,7 +310,7 @@ parent `Board` component instead of in each `Square` component. The `Board` comp
307310
Let's take this opportunity to try it out. Edit the `Board` component so that it declares a state
308311
variable named squares that defaults to an array of 9 nulls corresponding to the 9 squares:
309312

310-
```tsx
313+
```jsx
311314
import { create } from 'zustand'
312315
import { combine } from 'zustand/middleware'
313316

@@ -354,7 +357,7 @@ export default function Board() {
354357
array corresponds to the value of a square. When you fill the board in later, the squares array
355358
will look like this:
356359

357-
```ts
360+
```js
358361
const squares = ['O', null, 'X', 'X', 'X', 'O', 'O', null, null]
359362
```
360363

@@ -374,7 +377,7 @@ Now you'll connect the `onSquareClick` prop to a function in the `Board` compone
374377
`handleClick`. To connect `onSquareClick` to `handleClick` you'll pass an inline function to the
375378
`onSquareClick` prop of the first Square component:
376379

377-
```tsx
380+
```jsx
378381
<Square key={squareIndex} value={square} onSquareClick={() => handleClick(i)} />
379382
```
380383

@@ -385,12 +388,10 @@ The `handleClick` function should take the index of the square to update and cre
385388
`squares` array (`nextSquares`). Then, `handleClick` updates the `nextSquares` array by adding `X`
386389
to the square at the specified index (`i`) if is not already filled.
387390

388-
```tsx {7-12,29}
391+
```jsx {5-10,27}
389392
export default function Board() {
390-
const [squares, setSquares] = useGameStore((state) => [
391-
state.squares,
392-
state.setSquares,
393-
])
393+
const squares = useGameStore((state) => state.squares)
394+
const setSquares = useGameStore((state) => state.setSquares)
394395

395396
function handleClick(i) {
396397
if (squares[i]) return
@@ -434,7 +435,7 @@ board.
434435
You'll set the first move to be `'X'` by default. Let's keep track of this by adding another piece
435436
of state to the `useGameStore` hook:
436437

437-
```tsx {2,12-18}
438+
```jsx {2,12-18}
438439
const useGameStore = create(
439440
combine({ squares: Array(9).fill(null), xIsNext: true }, (set) => {
440441
return {
@@ -463,16 +464,12 @@ Each time a player moves, `xIsNext` (a boolean) will be flipped to determine whi
463464
and the game's state will be saved. You'll update the Board's `handleClick` function to flip the
464465
value of `xIsNext`:
465466

466-
```tsx {2-5,10,15}
467+
```jsx {2-3,6,11}
467468
export default function Board() {
468-
const [xIsNext, setXIsNext] = useGameStore((state) => [
469-
state.xIsNext,
470-
state.setXIsNext,
471-
])
472-
const [squares, setSquares] = useGameStore((state) => [
473-
state.squares,
474-
state.setSquares,
475-
])
469+
const xIsNext = useGameStore((state) => state.xIsNext)
470+
const setXIsNext = useGameStore((state) => state.setXIsNext)
471+
const squares = useGameStore((state) => state.squares)
472+
const setSquares = useGameStore((state) => state.setSquares)
476473
const player = xIsNext ? 'X' : 'O'
477474

478475
function handleClick(i) {
@@ -516,7 +513,7 @@ same array, checks for remaining turns by filtering out only `null` items, and r
516513
them. The last helper called `calculateStatus` that takes the remaining turns, the winner, and the
517514
current player (`'X' or 'O'`):
518515

519-
```ts
516+
```js
520517
function calculateWinner(squares) {
521518
const lines = [
522519
[0, 1, 2],
@@ -555,7 +552,7 @@ function to check if a player has won. You can perform this check at the same ti
555552
user has clicked a square that already has a `'X'` or and `'O'`. We'd like to return early in
556553
both cases:
557554

558-
```ts {2}
555+
```js {2}
559556
function handleClick(i) {
560557
if (squares[i] || winner) return
561558
const nextSquares = squares.slice()
@@ -570,16 +567,12 @@ To let the players know when the game is over, you can display text such as `'Wi
570567
display the winner or draw if the game is over and if the game is ongoing you'll display which
571568
player's turn is next:
572569

573-
```tsx {10-11,13,25}
570+
```jsx {6-7,9,21}
574571
export default function Board() {
575-
const [xIsNext, setXIsNext] = useGameStore((state) => [
576-
state.xIsNext,
577-
state.setXIsNext,
578-
])
579-
const [squares, setSquares] = useGameStore((state) => [
580-
state.squares,
581-
state.setSquares,
582-
])
572+
const xIsNext = useGameStore((state) => state.xIsNext)
573+
const setXIsNext = useGameStore((state) => state.setXIsNext)
574+
const squares = useGameStore((state) => state.squares)
575+
const setSquares = useGameStore((state) => state.setSquares)
583576
const winner = calculateWinner(squares)
584577
const turns = calculateTurns(squares)
585578
const player = xIsNext ? 'X' : 'O'
@@ -622,7 +615,7 @@ export default function Board() {
622615
Congratulations! You now have a working tic-tac-toe game. And you've just learned the basics of
623616
React and Zustand too. So you are the real winner here. Here is what the code should look like:
624617
625-
```tsx
618+
```jsx
626619
import { create } from 'zustand'
627620
import { combine } from 'zustand/middleware'
628621
@@ -672,14 +665,10 @@ function Square({ value, onSquareClick }) {
672665
}
673666

674667
export default function Board() {
675-
const [xIsNext, setXIsNext] = useGameStore((state) => [
676-
state.xIsNext,
677-
state.setXIsNext,
678-
])
679-
const [squares, setSquares] = useGameStore((state) => [
680-
state.squares,
681-
state.setSquares,
682-
])
668+
const xIsNext = useGameStore((state) => state.xIsNext)
669+
const setXIsNext = useGameStore((state) => state.setXIsNext)
670+
const squares = useGameStore((state) => state.squares)
671+
const setSquares = useGameStore((state) => state.setSquares)
683672
const winner = calculateWinner(squares)
684673
const turns = calculateTurns(squares)
685674
const player = xIsNext ? 'X' : 'O'
@@ -765,7 +754,7 @@ You'll keep track of these past squares arrays in a new state variable called `h
765754
`history` array will store all board states, from the first move to the latest one, and will look
766755
something like this:
767756

768-
```ts
757+
```js
769758
const history = [
770759
// First move
771760
[null, null, null, null, null, null, null, null, null],
@@ -793,16 +782,12 @@ component data and instruct the `Board` component to render previous turns from
793782
First, add a `Game` component with `export default` and remove it from `Board` component. Here is
794783
what the code should look like:
795784

796-
```tsx {1,48-65}
785+
```jsx {1,44-61}
797786
function Board() {
798-
const [xIsNext, setXIsNext] = useGameStore((state) => [
799-
state.xIsNext,
800-
state.setXIsNext,
801-
])
802-
const [squares, setSquares] = useGameStore((state) => [
803-
state.squares,
804-
state.setSquares,
805-
])
787+
const xIsNext = useGameStore((state) => state.xIsNext)
788+
const setXIsNext = useGameStore((state) => state.setXIsNext)
789+
const squares = useGameStore((state) => state.squares)
790+
const setSquares = useGameStore((state) => state.setSquares)
806791
const winner = calculateWinner(squares)
807792
const turns = calculateTurns(squares)
808793
const player = xIsNext ? 'X' : 'O'
@@ -854,7 +839,7 @@ export default function Game() {
854839
<Board />
855840
</div>
856841
<div style={{ marginLeft: '1rem' }}>
857-
<ol>{/*TODO*/}</ol>
842+
<ol>{/* TODO */}</ol>
858843
</div>
859844
</div>
860845
)
@@ -863,7 +848,7 @@ export default function Game() {
863848

864849
Add some state to the `useGameStore` hook to track the history of moves:
865850

866-
```ts {2,4-11}
851+
```js {2,4-11}
867852
const useGameStore = create(
868853
combine({ history: [Array(9).fill(null)], xIsNext: true }, (set) => {
869854
return {
@@ -895,9 +880,12 @@ To render the squares for the current move, you'll need to read the most recent
895880
the `history` state. You don't need an extra state for this because you already have enough
896881
information to calculate it during rendering:
897882

898-
```tsx {2-3}
883+
```jsx {2-6}
899884
export default function Game() {
900-
const { history, setHistory, xIsNext, setXIsNext } = useGameStore()
885+
const history = useGameStore((state) => state.history)
886+
const setHistory = useGameStore((state) => state.setHistory)
887+
const xIsNext = useGameStore((state) => state.xIsNext)
888+
const setXIsNext = useGameStore((state) => state.setXIsNext)
901889
const currentSquares = history[history.length - 1]
902890

903891
return (
@@ -923,9 +911,12 @@ Next, create a `handlePlay` function inside the `Game` component that will be ca
923911
component to update the game. Pass `xIsNext`, `currentSquares` and `handlePlay` as props to the
924912
`Board` component:
925913

926-
```tsx {5-7,18}
914+
```jsx {8-10,21}
927915
export default function Game() {
928-
const { history, setHistory, xIsNext, setXIsNext } = useGameStore()
916+
const history = useGameStore((state) => state.history)
917+
const setHistory = useGameStore((state) => state.setHistory)
918+
const currentMove = useGameStore((state) => state.currentMove)
919+
const setCurrentMove = useGameStore((state) => state.setCurrentMove)
929920
const currentSquares = history[history.length - 1]
930921

931922
function handlePlay(nextSquares) {
@@ -955,7 +946,7 @@ Let's make the `Board` component fully controlled by the props it receives. To d
955946
the `Board` component to accept three props: `xIsNext`, `squares`, and a new `onPlay` function that
956947
the `Board` component can call with the updated squares array when a player makes a move.
957948

958-
```tsx {1}
949+
```jsx {1}
959950
function Board({ xIsNext, squares, onPlay }) {
960951
const winner = calculateWinner(squares)
961952
const turns = calculateTurns(squares)
@@ -1008,7 +999,7 @@ squares array as a new `history` entry. You also need to toggle `xIsNext`, just
1008999
component used
10091000
to do.
10101001

1011-
```ts {2-3}
1002+
```js {2-3}
10121003
function handlePlay(nextSquares) {
10131004
setHistory(history.concat([nextSquares]))
10141005
setXIsNext(!xIsNext)
@@ -1018,7 +1009,7 @@ function handlePlay(nextSquares) {
10181009
At this point, you've moved the state to live in the `Game` component, and the UI should be fully
10191010
working, just as it was before the refactor. Here is what the code should look like at this point:
10201011

1021-
```tsx
1012+
```jsx
10221013
import { create } from 'zustand'
10231014
import { combine } from 'zustand/middleware'
10241015

@@ -1106,7 +1097,10 @@ function Board({ xIsNext, squares, onPlay }) {
11061097
}
11071098

11081099
export default function Game() {
1109-
const { history, setHistory, xIsNext, setXIsNext } = useGameStore()
1100+
const history = useGameStore((state) => state.history)
1101+
const setHistory = useGameStore((state) => state.setHistory)
1102+
const xIsNext = useGameStore((state) => state.xIsNext)
1103+
const setXIsNext = useGameStore((state) => state.setXIsNext)
11101104
const currentSquares = history[history.length - 1]
11111105

11121106
function handlePlay(nextSquares) {
@@ -1178,9 +1172,12 @@ You'll use `map` to transform your `history` of moves into React elements repres
11781172
screen, and display a list of buttons to **jump** to past moves. Let's `map` over the `history` in
11791173
the `Game` component:
11801174

1181-
```tsx {26-41}
1175+
```jsx {29-44}
11821176
export default function Game() {
1183-
const { history, setHistory, xIsNext, setXIsNext } = useGameStore()
1177+
const history = useGameStore((state) => state.history)
1178+
const setHistory = useGameStore((state) => state.setHistory)
1179+
const xIsNext = useGameStore((state) => state.xIsNext)
1180+
const setXIsNext = useGameStore((state) => state.setXIsNext)
11841181
const currentSquares = history[history.length - 1]
11851182

11861183
function handlePlay(nextSquares) {
@@ -1230,7 +1227,7 @@ Before you can implement the `jumpTo` function, you need the `Game` component to
12301227
step the user is currently viewing. To do this, define a new state variable called `currentMove`,
12311228
which will start at `0`:
12321229

1233-
```ts {3,14-21}
1230+
```js {3,14-21}
12341231
const useGameStore = create(
12351232
combine(
12361233
{ history: [Array(9).fill(null)], currentMove: 0, xIsNext: true },
@@ -1269,7 +1266,7 @@ const useGameStore = create(
12691266
Next, update the `jumpTo` function inside `Game` component to update that `currentMove`. You’ll
12701267
also set `xIsNext` to `true` if the number that you’re changing `currentMove` to is even.
12711268

1272-
```ts {2-3}
1269+
```js {2-3}
12731270
function jumpTo(nextMove) {
12741271
setCurrentMove(nextMove)
12751272
setXIsNext(currentMove % 2 === 0)
@@ -1285,7 +1282,7 @@ when you click on a square.
12851282
`history.slice(0, currentMove + 1)` to keep only that portion of the old history.
12861283
- Each time a move is made, you need to update `currentMove` to point to the latest history entry.
12871284

1288-
```ts {2-4}
1285+
```js {2-4}
12891286
function handlePlay(nextSquares) {
12901287
const nextHistory = history.slice(0, currentMove + 1).concat([nextSquares])
12911288
setHistory(nextHistory)
@@ -1297,16 +1294,14 @@ function handlePlay(nextSquares) {
12971294
Finally, you will modify the `Game` component to render the currently selected move, instead of
12981295
always rendering the final move:
12991296

1300-
```tsx {2-10}
1297+
```jsx {2-8}
13011298
export default function Game() {
1302-
const {
1303-
history,
1304-
setHistory,
1305-
currentMove,
1306-
setCurrentMove,
1307-
xIsNext,
1308-
setXIsNext,
1309-
} = useGameStore()
1299+
const history = useGameStore((state) => state.history)
1300+
const setHistory = useGameStore((state) => state.setHistory)
1301+
const currentMove = useGameStore((state) => state.currentMove)
1302+
const setCurrentMove = useGameStore((state) => state.setCurrentMove)
1303+
const xIsNext = useGameStore((state) => state.xIsNext)
1304+
const setXIsNext = useGameStore((state) => state.setXIsNext)
13101305
const currentSquares = history[currentMove]
13111306

13121307
function handlePlay(nextSquares) {
@@ -1365,9 +1360,12 @@ There's no need to store `xIsNext` separately in the state. It’s better to avo
13651360
because it can reduce bugs and make your code easier to understand. Instead, you can calculate
13661361
`xIsNext` based on `currentMove`:
13671362

1368-
```tsx {2,10,14}
1363+
```jsx {2-5,13,17}
13691364
export default function Game() {
1370-
const { history, setHistory, currentMove, setCurrentMove } = useGameStore()
1365+
const history = useGameStore((state) => state.history)
1366+
const setHistory = useGameStore((state) => state.setHistory)
1367+
const currentMove = useGameStore((state) => state.currentMove)
1368+
const setCurrentMove = useGameStore((state) => state.setCurrentMove)
13711369
const xIsNext = currentMove % 2 === 0
13721370
const currentSquares = history[currentMove]
13731371

0 commit comments

Comments
 (0)