Skip to content

Commit 30bdf7f

Browse files
committed
Finished useCallback section
1 parent 3513c26 commit 30bdf7f

1 file changed

Lines changed: 51 additions & 31 deletions

File tree

  • epic-react-kent-c-dodds/03-Advanced-React-Hooks/src/exercise

epic-react-kent-c-dodds/03-Advanced-React-Hooks/src/exercise/02.js

Lines changed: 51 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,27 @@ import {
1010
PokemonErrorBoundary,
1111
} from '../pokemon'
1212

13+
function useSafeDispatch(dispatch) {
14+
const mountedRef = React.useRef(false)
15+
16+
React.useEffect(() => {
17+
mountedRef.current = true
18+
// Cleanup function
19+
return () => {
20+
mountedRef.current = false
21+
}
22+
}, [])
23+
24+
return React.useCallback(
25+
(...args) => {
26+
if (mountedRef.current) {
27+
dispatch(...args)
28+
}
29+
},
30+
[dispatch],
31+
)
32+
}
33+
1334
function asyncReducer(state, action) {
1435
switch (action.type) {
1536
case 'pending': {
@@ -31,45 +52,44 @@ function asyncReducer(state, action) {
3152
}
3253

3354
// Custom hook for using async functions with data retreiving.
34-
const useAsync = (asyncCallback, initialState, dependencies) => {
35-
const [state, dispatch] = React.useReducer(asyncReducer, {
55+
const useAsync = initialState => {
56+
const [state, unsafeDispatch] = React.useReducer(asyncReducer, {
3657
status: 'idle',
3758
data: null,
3859
error: null,
3960
...initialState,
4061
})
41-
React.useEffect(() => {
42-
const promise = asyncCallback()
43-
if (!promise) {
44-
return
45-
}
46-
dispatch({type: 'pending'})
47-
promise.then(
48-
data => {
49-
dispatch({type: 'resolved', data})
50-
},
51-
error => {
52-
dispatch({type: 'rejected', error})
53-
},
54-
)
55-
// eslint-disable-next-line react-hooks/exhaustive-deps
56-
}, dependencies)
57-
return state
58-
}
5962

60-
function PokemonInfo({pokemonName}) {
61-
// Executing our custom hook.
62-
const state = useAsync(
63-
() => {
64-
if (!pokemonName) {
65-
return
66-
}
67-
return fetchPokemon(pokemonName)
63+
const dispatch = useSafeDispatch(unsafeDispatch)
64+
65+
const run = React.useCallback(
66+
promise => {
67+
dispatch({type: 'pending'})
68+
promise.then(
69+
data => {
70+
dispatch({type: 'resolved', data})
71+
},
72+
error => {
73+
dispatch({type: 'rejected', error})
74+
},
75+
)
6876
},
69-
{status: pokemonName ? 'pending' : 'idle'},
70-
[pokemonName],
77+
[dispatch],
7178
)
72-
const {data: pokemon, status, error} = state
79+
return {...state, run}
80+
}
81+
82+
function PokemonInfo({pokemonName}) {
83+
const {data: pokemon, status, error, run} = useAsync({
84+
status: pokemonName ? 'pending' : 'idle',
85+
})
86+
87+
React.useEffect(() => {
88+
if (!pokemonName) {
89+
return
90+
}
91+
run(fetchPokemon(pokemonName))
92+
}, [pokemonName, run])
7393

7494
if (status === 'idle' || !pokemonName) {
7595
return 'Submit a pokemon'

0 commit comments

Comments
 (0)