🍀
React + unstated-nextを使って、非同期(async/await)で値を管理
React hooksとunstated-nextを活用することで、処理とコンポーネントを分離し、非同期であることを意識せず値をやり取りすることができます。
また、unstated-nextのソースコードはたった40行で、useContextを扱いやすくするためのモジュールであるため、簡単にReact hooksのみのネイティブな実装に書き換えることができます。
フックをコンテナ化
props-container.ts
import { useState } from "react";
import { createContainer } from "unstated-next";
const hooks = (initialState: string = "") => {
const [props, setProps] = useState(initialState);
const updateProps = async (arg: string) => {
// 処理中であることを通知
setProps("processing...🐢");
// 重たい処理
const heavyProcess = new Promise<string>(resolve =>
setTimeout(() => resolve(arg + " finished🎉"), 1000)
);
// 重たい処理の返り値
const response = await heavyProcess;
// 結果を出力
setProps(response);
};
return { props, updateProps };
};
export default createContainer(hooks);
setPropsはコンテナ内で使用し、外部からはupdatePropsのみを使用します。updatePropsを外部から呼び出すことで、引数に指定した値が非同期処理終了後、propsに格納されます。
サンプルコードでは処理中であることを示す値をセットしていますが、非同期処理が完了するまで値を変更する必要がない場合は、updatePropsの最初のsetPropsは必要ありません。
Provider以下のコンポーネントで、コンテナを使用できるようにする
app.tsx
import React from "react";
import PropsContainer from "./props-container";
import Form from "./Form";
// Provider以下のコンポーネントであれば、useContainerで共通のフックを使用できます
const App: React.FC = () => (
<PropsContainer.Provider initialState={"init"}>
<Form />
</PropsContainer.Provider>
);
export default App;
サンプルコードの子要素が1つだけなので余り恩恵はありませんが、Providerを定義することで子要素のコンポーネント全てで先ほどのコンテナを使用できます。
この辺りはuseContextと同様です。
コンテナを使用する
form.tsx
import React from "react";
import PropsContainer from "./props-container";
const Form: React.FC = () => {
// コンテナ内のフックを呼び出す
const { props, updateProps } = PropsContainer.useContainer();
const [input, setInput] = React.useState("");
// 値を扱う際に非同期であることを意識する必要はない
const update = () => updateProps(input);
const onChangeInput = (e: React.ChangeEvent<HTMLInputElement>) =>
setInput(e.target.value);
return (
<div>
<input type="text" value={input} onChange={onChangeInput} />
<button onClick={update}>update</button>
<h1>{props}</h1>
</div>
);
};
export default Form;
コンポーネントサイドでは、updatePropsの引数が非同期で設定されることを意識する必要はありません。
以上で、以下のような実装を実現できます。
以上が現在私が活用している方法です。まだまだ勉強不足なところもあり、どうすれば最適なのかしっかり把握できている自信はありません。
もっといい方法をご存知でしたらご教授ください🙇♂️
Discussion