Skip to content

Commit

Permalink
add instructions
Browse files Browse the repository at this point in the history
  • Loading branch information
kentcdodds committed Mar 12, 2024
1 parent 10a3243 commit 4cb4040
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 3 deletions.
39 changes: 39 additions & 0 deletions exercises/01.use-reducer/06.problem.tic-tac-toe/README.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,43 @@
We'll be refactoring the `useState` out of our tic-tac-toe game to use
`useReducer` instead.

Your reducer should enable the following actions:

```tsx
type GameAction =
| { type: 'SELECT_SQUARE'; index: number }
| { type: 'SELECT_STEP'; step: number }
| { type: 'RESTART' }

function gameReducer(state: GameState, action: GameAction) {
// your code...
}
```

Note that to do the lazy state initialization we need to provide three arguments
to `useReducer`. Here's an example for a count reducer:

```tsx
// ...
function getInitialState(initialCount: number) {
return { count: initialCount }
}

function Counter() {
const [count, dispatch] = useReducer(
countReducer,
props.initialCount,
getInitialState,
)
// ...
}
```

Notice that the `getInitialState` function is called only once, when the
component is first rendered and it's called with the `initialCount` prop which
is passed to the `useReducer` hook as the second argument.

If you don't need an argument to your initial state callback, you can just pass
`null`.

Good luck!
23 changes: 22 additions & 1 deletion exercises/01.use-reducer/06.problem.tic-tac-toe/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,25 @@ function Board({
)
}

const defaultState = {
const defaultState: GameState = {
history: [Array(9).fill(null)],
currentStep: 0,
}

const localStorageKey = 'tic-tac-toe'

// 🦺 Create a GameAction type here which supports all three types of state changes
// that can happen for our reducer: SELECT_SQUARE, RESTART, and SELECT_STEP.

// 🐨 Create a gameStateReducer function which accepts the GameState and GameAction
// and handle all three types of state changes.
// 💰 you can borrow lots of the logic from the component below in your implementation

// 🐨 Create a getInitialGameState function here which returns the initial game
// state (move this from the useState callback below)

function App() {
// 🐨 change this to use useReducer with the gameStateReducer and the getInitialGameState function
const [state, setState] = useState<GameState>(() => {
let localStorageValue
try {
Expand All @@ -79,6 +91,8 @@ function App() {
}, [state])

function selectSquare(index: number) {
// 🐨 move this logic to the reducer
// then call the dispatch function with the proper type
if (winner || currentSquares[index]) return

setState(previousState => {
Expand All @@ -94,6 +108,7 @@ function App() {
}

function restart() {
// 🐨 update this to use the dispatch function with the proper type
setState(defaultState)
}

Expand All @@ -107,6 +122,7 @@ function App() {
return (
<li key={step}>
<button
// 🐨 update this to use the dispatch function with the proper type
onClick={() =>
setState(previousState => ({ ...previousState, currentStep: step }))
}
Expand Down Expand Up @@ -139,3 +155,8 @@ function App() {
const rootEl = document.createElement('div')
document.body.append(rootEl)
ReactDOM.createRoot(rootEl).render(<App />)

/*
eslint
@typescript-eslint/no-unused-vars: "off",
*/
8 changes: 6 additions & 2 deletions exercises/01.use-reducer/06.solution.tic-tac-toe/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,12 @@ function gameStateReducer(state: GameState, action: GameAction) {
case 'SELECT_SQUARE': {
const { currentStep, history } = state
const newHistory = history.slice(0, currentStep + 1)
const squares = history[currentStep].with(
const currentSquares = history[currentStep]
const winner = calculateWinner(currentSquares)

if (winner || currentSquares[action.index]) return state

const squares = currentSquares.with(
action.index,
calculateNextValue(history[currentStep]),
)
Expand Down Expand Up @@ -116,7 +121,6 @@ function App() {
}, [state])

function selectSquare(index: number) {
if (winner || currentSquares[index]) return
dispatch({ type: 'SELECT_SQUARE', index })
}

Expand Down

0 comments on commit 4cb4040

Please sign in to comment.