React Hooks の useReducer と向き合う

useState で誤魔化していたのだけど、使ってみたら案外便利かも?とおもってちょっと素振りした
仕事で Apollo を使っていて便利なのだけど、別件では未だに REST なので、Apollo っぽいインターフェースで REST を叩けることを目標にする

index.tsx

              enum DATA_FETCH_ACTION {
  FETCH_COMPLETE = 'FETCH_COMPLETE'
}

interface DataFetchState<T> {
  loading: boolean
  error: Maybe<Error>
  data: Maybe<T>
}

interface DataFetchAction<T> {
  type: DATA_FETCH_ACTION
  payload: T
  error?: boolean
}

const dataFetchReducer = <T>(
  state: DataFetchState<T>,
  action: DataFetchAction<T>
): DataFetchState<T> => {
  switch (action.type) {
    case DATA_FETCH_ACTION.FETCH_COMPLETE: {
      return {
        ...state,
        loading: false,
        data: action.payload
      }
    }
  }
  return state
}

const useRequest = <T>(url: string) => {
  const [state, dispatch] = useReducer<
    React.Reducer<DataFetchState<T>, DataFetchAction<T>>
  >(dataFetchReducer, {
    loading: true,
    error: null,
    data: null
  })
  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(json => {
        if (json.data) {
          dispatch({
            type: DATA_FETCH_ACTION.FETCH_COMPLETE,
            payload: json.data as T
          })
        } else {
          // TODO
        }
      })
  }, [])
  return state
}
            
ざっくり共通リクエスト部分

index.tsx

              export const useFoo = ({ id }: Params) {
  const state = useRequest<FooResponse>(`/api/foo/${id}`)
  return state
}
            

こんな感じで hook を用意しておくと、コンポーネント側から Apollo ライクに呼び出してハンドリングしてあげるだけでアプリケーションが組み立てられて便利
まだエラーハンドリングとかはやってないのでおいおいということで...