🐡
Loan Pattern でLoading Stateを管理
モチベーション
loading stateはthrid party のfetch client を使用しないSPAの場合、同じような処理を複数書く必要が出て、面倒な実装かと思います。本来loan pattern はリソースの解放を行う際にScalaなどでよく用いられるデザインパターンですが、任意の処理に対して必ず実行したい処理、といった意味ではFrontendにおいてはLoading Stateとリソース管理の類似性を感じました。
そこで、本来の使用意図とは異なりますが、Frontend(React)における、LoanPatternLikeな実装の例としてLoadingStateを例としてその実装の簡素さを表現してみたいと思います。
今回は、typescript のusingを使用して、loan pattern でloading のtrue/ false を管理する実装を実践していきます。
前提条件
具体的な実装
編集対象のfiles
- app/tsconfig.app.json
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "esnext",
"useDefineForClassFields": true,
"lib": ["esnext", "DOM", "DOM.Iterable","esnext.disposable"], // add : "esnext.disposable"
"module": "ESNext",
"skipLibCheck": true,
"experimentalDecorators": true, // add
...
- app/vite.config.ts
export default defineConfig({
plugins: [react({
babel: {
plugins: ["@babel/plugin-proposal-explicit-resource-management"], // add @babel/plugin-proposal-explicit-resource-management
}
})],
})
具体的な実装
- class
esnext.disposableをlibsに追加することによってDisposableが使えるようになります
export class LoadingState implements Disposable {
constructor(private setLoading: (loading: boolean) => void) {
this.setLoading(true);
}
[Symbol.dispose]() {
this.setLoading(false);
}
}
- component
import { useState } from 'react';
import { LoadingState } from '../classes/LoadingState';
export const MyComponent = () => {
const [loading, setLoading] = useState(false);
async function fetchData() {
using _loading = new LoadingState(setLoading);
// データ取得処理
await new Promise(resolve => setTimeout(resolve, 2000)); // 例: 2秒間の非同期処理
console.log('Data fetched');
}
return (
<div>
{loading && <p>Loading...</p>}
<button onClick={fetchData}>Fetch Data</button>
</div>
);
}
処理の説明
using _loading = new LoadingState(setLoading);
この箇所でusingを使用しています
scopeを抜けると、ここで宣言されたLoadingStateのdisposeが発火し、this.setLoading(false)となる、といった感じです
Discussion
もしご存知でしたら余計なお世話になってしまいますが、
React 19 を使っている場合は、action の機能(たとえば、
useTransition
)を使うことでローディング状態をファーストクラスで扱うことが可能になります!コメントありがとうございます。
あくまで上記の通りですので、具体として分かりやすい例がloadingであると言うだけで、主眼は抽象(任意の処理に対して必ず実行したい処理)にあります。
具体に対する方法の別解としては適格ですが、主眼は具体にはない点だけご認識いただければと思います。
なるほどそうだったんですね!失礼しました🙇♂️