import React from 'react'; import ListGroup from 'react-bootstrap/ListGroup'; import { url } from '../../shared/jokes-api'; import Loading from '../../shared/loading'; function reducer(state, action) { switch (action.type) { case 'loaded': return { ...state, loading: false, jokes: action.payload }; case 'error-loading': return { ...state, loading: false, error: action.payload }; default: return state; } } function useThunkedReducer(reducer, initialState) { const [state, dispatch] = React.useReducer(reducer, initialState); const thunkedDispatch = React.useCallback( action => { if (typeof action === 'function') { action(thunkedDispatch, state); } else { dispatch(action); } }, [dispatch, state] ); return [state, thunkedDispatch]; } async function fetchData(dispatch, state) { if (state.jokes) return; try { const rsp = await fetch(url); if (rsp.ok) { const data = await rsp.json(); dispatch({ type: 'loaded', payload: data.value }); } else { throw new Error(rsp.statusText); } } catch (e) { dispatch({ type: 'error-loading', payload: e }); } } function useJokes(url) { const [state, dispatch] = useThunkedReducer(reducer, { jokes: null, error: null, loading: true }); React.useEffect(() => { dispatch(fetchData); }); return state; } const FetchWithCustomHooks = () => { const { loading, error, jokes } = useJokes(url); if (loading) { return <Loading />; } if (error) { return <div>{error && error.message}</div>; } return ( <ListGroup> {jokes.map(item => ( <ListGroup.Item key={item.id}>{item.joke}</ListGroup.Item> ))} </ListGroup> ); }; export default FetchWithCustomHooks;