Skip to content

Instantly share code, notes, and snippets.

@mithi
Last active January 28, 2021 15:53
Show Gist options
  • Save mithi/45d98c7ae55d48b59aa159aa43a4dd15 to your computer and use it in GitHub Desktop.
Save mithi/45d98c7ae55d48b59aa159aa43a4dd15 to your computer and use it in GitHub Desktop.

Also about exercise 2, extra credit 3... The solution has this:

function asyncReducer(state, action) {
  switch (action.type) {
    case 'pending': {
      return {status: 'pending', data: null, error: null}
    }
    case 'resolved': {
      return {status: 'resolved', data: action.data, error: null}
    }
    case 'rejected': {
      return {status: 'rejected', data: null, error: action.error}
    }
    default: {
      throw new Error(`Unhandled action type: ${action.type}`)
    }
  }
}

function useAsync(initialState) {
  const [state, unsafeDispatch] = React.useReducer(asyncReducer, {
    status: 'idle', data: null, error: null, ...initialState,
  })

  const dispatch = useSafeDispatch(unsafeDispatch)
  const {data, error, status} = state

  const run = React.useCallback(
    promise => {
      dispatch({ type: 'pending' })
      promise.then(
        data => { dispatch({ type: 'resolved', data }) },
        error => { dispatch({ type: 'rejected', error }) },
      )
    },
    [dispatch],
  )

  return { error, status, data, run }
}

aside from not following convention, why is it not advisable to do this instead?

function asyncReducer(state, action) {
  const possibleStatus = ['pending', 'resolved', 'rejected']

  if (possibleStatus.includes(action.status)) {
    return action
  }

  throw new Error(`Status is not handled: ${action.status}`
}

function useAsync(initialState) {
  const [state, unsafeDispatch] = React.useReducer(asyncReducer, {
    status: 'idle', data: null, error: null, ...initialState,
  })

  const dispatch = useSafeDispatch(unsafeDispatch)

  const {data, error, status} = state

  const run = React.useCallback(
    promise => {
      dispatch({ status: 'pending' })
      promise.then(
        data => { dispatch({ status: 'resolved', data }) },
        error => { dispatch({ status: 'rejected', error }) },
      )
    },
    [dispatch],
  )

  return { error, status, data, run }
}
@mithi
Copy link
Author

mithi commented Jan 28, 2021

A reply

your solution allows to reach states that should be impossible, e.g.: dispatch({ status: 'resolved', error })

My response:

But the useAsync hook (which is the only one that uses the asyncReducer) won't allow that to happen.... Since useAsync is something we wrote ourselves, then we don't need to worry that asyncReducer would be misused by other people... I'm assuming that asyncReducer hook is a private function that is only accessible to useAsync. Is there a use case where asyncReducer should be available to the public?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment