Api の呼び出しを hooks で囲うのはイマイチかも

2021-04-02

「Api の呼び出しはすべてグローバルな hooks から呼び出す」というルールが敷かれているプロジェクトをちょくちょく目にしますが。

そのせいでうまいこと実装できないケースに出会ったので、備忘録がてら書いていこうと思います。


まず Api の呼び出しを以下の通りとします。

type GetHogeParams = { fuga: string; }; type GetHogeData = { piyo: number; }; const getHoge = (params: GetHogeParams) => axios.get<GetHogeData>("/api/hoge", { params, });

続いて getHoge を呼び出す hooks を切ります。

const getHogeHooks = (params: GetHogeParams) => { const [piyo, setPiyo] = useState<GetHogeData["piyo"] | undefined>(); useEffect(() => { const callback = async () => { const { data: { piyo }, } = await getHoge(params); setPiyo(piyo); }; callback(); }, [params]); return piyo; };

最後に getHogeHooks を呼び出します。

const Moge: FC = () => { const piyo = getHogeHooks({ fuga: "fugafuga" }); return typeof piyo === "undefined" ? null : <div>{piyo}</div>; };

ぱっと見なにも問題なさそうですが、この書き方では例えば以下のようなケースは対応できません。

type MogeProps = { fuga?: string; }; const Moge: FC<MogeProps> = ({ fuga }: MogeProps) => { // props.fuga は undefined を許容しているため渡せない… const piyo = getHogeHooks({ fuga }); return typeof piyo === "undefined" ? null : <div>{piyo}</div>; };

そのため、hooks はまだこう書いたほうがマシかなーと思いますが…。

const getHogeHooks = () => { const callback = useCallback((params: GetHogeParams) => getHoge(params), []); return callback; };

個人的な意見として、そもそもグローバルな hooks のみ Api の呼び出しを許容する設計自体が必要ないんじゃないか?と思います。

なので普通にこう書けば良いのでは?とは思います。

type MogeProps = { fuga?: string; }; const Moge: FC<MogeProps> = ({ fuga }: MogeProps) => { const [piyo, setPiyo] = useState<GetHogeData["piyo"] | undefined>(); useEffect(() => { const callback = async () => { if (typeof fuga !== "string") { return; } const { data: { piyo }, } = await getHoge({ fuga }); setPiyo(piyo); }; callback(); }, [params]); return typeof piyo === "undefined" ? null : <div>{piyo}</div>; };

もちろんケースバイケースだとは思いますが、意外とやってしまいそうな実装だったので備忘録がてら。

© 2018 kk-web