React SDK
React と Squid を統合するためのライブラリ。
Features
- Squid Client の collections、documents、queries へのアクセス用のフック。
- React コンポーネント内のどこからでも Squid Client へアクセスできる Provider。
Getting started
Requirements
この SDK を利用するには、React のバージョン 16.11 以降が必要です。
Installation
NPM を使って Squid React SDK をインストールします:
npm install @squidcloud/react
Configure Squid
-
Squid Console にアクセスし、Create application をクリックしてアプリケーションを作成します。
-
新しく作成したアプリケーションの Overview タブから
Application IDをコピーします。 -
以下の Provider を React アプリケーションに追加します:
// main.tsx
import { SquidContextProvider } from '@squidcloud/react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<SquidContextProvider
options={{
appId: '<SQUID_CLOUD_APP_ID>',
region: '<SQUID_CLOUD_REGION>',
}}
>
<App />
</SquidContextProvider>
);
注意: 環境管理に .env ファイルを使用している場合、appId と region を希望する envars に設定してください:
// main.tsx
<SquidContextProvider
options={{
appId: process.env.SQUID_CLOUD_APP_ID,
region: process.env.SQUID_CLOUD_REGION,
}}
>
Hooks
アプリケーションを SquidContextProvider でラップすることで、Squid インスタンスへアクセスできるようになります。このインスタンスに直接アクセスするには、useSquid フックを使用してください。
function App() {
const squid = useSquid();
const foo = () => {
squid.executeFunction('foo');
};
return <button onClick={foo}>Foo</button>;
}
しかしながら、collections、queries、documents へのアクセスを提供する追加のフックも用意されています。
useCollection
useCollection フックは、squid.collection(...) のラッパーです。これにより、squid への参照なしにコレクションにアクセスできます。一度コレクションを取得すれば、そのコレクションを使ってクエリを作成したり、ドキュメントを管理することができます。
const collection = useCollection<User>('users');
const query = collection.query().eq('name', 'John Doe');
const doc = collection.doc('user-id');
useQuery
クエリが作成されたら、useQuery フックを使用して実行し、必要に応じて結果を subscribe します。
フックは以下のプロパティを含むオブジェクトを返します:
loading: クエリによってデータが返されたかどうか。data: クエリ結果の配列。渡されたクエリのタイプに応じて、これはドキュメント参照、ドキュメントデータ、ジョインクエリ結果などになる場合があります。error: クエリ実行時にエラーが発生した場合のエラーオブジェクト。
function App() {
const collection = useCollection<User>('users');
/**
* The list of docs will be streamed to the client and will be
* kept up-to-date.
*/
const { data } = useQuery(collection.query().gt('age', 18), {
subscribe: true,
initialData: [],
});
return (
<ul>
{docs.map((d) => (
<li key={d.refId}>{d.data.age}</li>
))}
</ul>
);
}
もし subscribe オプションが true に設定されている場合、データはクライアントにストリームされ、コンポーネントは新しい更新を受け取ると自動的に再レンダリングされます。subscribe が false の場合、クエリの初期データのみが取得され、変更はストリームされません。
オプションで、フックは最初の結果が読み込まれるまで返される initialData オプションを受け取ることもできます。
usePagination
usePagination フックは、クエリ結果をページネートするために使用されます。ページネーションを管理し、データを最新の状態に保つためのインターフェースを提供します。Squid のページネーションの詳細については、pagination documentation をご覧ください。
フックは以下のプロパティを含むオブジェクトを返します:
loading: 現在、データが読み込まれているか、ページネーションが行われているかどうか。data: ページネーションされた結果の配列。渡されたクエリのタイプに応じて、これはドキュメント参照、ドキュメントデータ、ジョインクエリ結果などになる場合があります。hasNext: 現在のページの後にさらに結果があるかどうかを示すブール値。hasPrev: 現在のページの前にさらに結果があるかどうかを示すブール値。next: 次の結果ページを読み込むための関数(hasNextが true の場合にのみ有効)。prev: 前の結果ページを読み込むための関数(hasPrevが true の場合にのみ有効)。
function App() {
const collection = useCollection<User>('users');
/**
* Paginate through the list of users.
* The list of docs will be streamed to the client and will be kept up-to-date.
*/
const { docs, loading, hasNext, hasPrev, next, prev } = usePagination(
collection.query().eq('age', 30).sortBy('name'),
{ subscribe: true, pageSize: 10 } /* PaginationOptions */,
[30] // deps
);
if (loading) {
return <div>Loading...</div>;
}
return (
<div>
<ul>
{docs.map((d) => (
<li key={d.refId}>{d.data.name}</li>
))}
</ul>
<button onClick={prev} disabled={!hasPrev}>
Previous
</button>
<button onClick={next} disabled={!hasNext}>
Next
</button>
</div>
);
}
もし subscribe オプションが true に設定されている場合、データはクライアントにストリームされ、コンポーネントは新しい更新を受け取ると自動的に再レンダリングされます。ページ内の最初と最後の項目の間に新しいデータが追加された場合、ページ上の項目は自動的に更新され、常に pageSize の項目のみが表示されます。
ページネーションを使用するには、クエリで sortBy を指定する必要があります。
オプションで、フックは deps 配列も受け取ることができます。deps 配列が変更されると、新しいページネーションクエリが作成されます。
useDoc
useDoc フックは同様の機能を提供しますが、クエリに対してサブスクライブするのではなく、特定のドキュメントの更新にサブスクライブします。
フックは以下のプロパティを含むオブジェクトを返します:
loading: ドキュメントクエリによってデータが返されたかどうか。data: ドキュメントデータ。データが受信されていない場合、またはドキュメントが削除された場合は undefined になります。error: ドキュメントのクエリ実行時にエラーが発生した場合のエラーオブジェクト。
// App.tsx
function App() {
const collection = useCollection<User>('users');
const doc = collection.doc('user-id');
/**
* Changes to the doc will be streamed to the client and it will be
* kept up-to-date.
*/
const { data } = useDoc(doc);
return <span>{data.foo}</span>;
}
useDocs
useDocs フックは、複数のドキュメント参照に対する更新を提供します。
フックは以下のプロパティを含むオブジェクトを返します:
loading: すべてのドキュメントクエリに対してデータが返されたかどうか。data: ドキュメントデータの配列。配列の要素は、データが受信されていない場合やドキュメントが削除された場合は undefined になることがあります。error: 任意のドキュメントのクエリ実行時にエラーが発生した場合のエラーオブジェクト。
// App.tsx
function App() {
const collection = useCollection<User>('users');
const docs = [collection.doc('my-id-1'), collection.doc('my-id-2')];
/**
* Changes to the documents will be streamed to the client and they will be
* kept up-to-date.
*/
const { data } = useDocs(docs);
return (
<ul>
<li>{data[0].foo}</li>
<li>{data[1].foo}</li>
</ul>
);
}
Async Hooks
Squid Client SDK は Promises と Observables を使用していますが、React コンポーネント内でこれらの非同期更新をサポートするために、いくつかの工夫が必要です。
すべての Squid Client SDK の機能が React に容易に統合できるよう、Squid は usePromise および useObservable フックを公開しています。これらのフックにより、React コンポーネント内で直接 squid インスタンス上の非同期関数を利用できます。
useObservable
useObservable フックは、Observable<T> を返す関数を受け取り、コンポーネント内でその Observable にサブスクライブして更新を受け取ることを可能にします。返されるオブジェクトは以下のプロパティを含みます:
loading: Observable から値が受け取られたかどうか。data: Observable から受け取った最新のデータ。error: Observable でエラーが発生した場合のエラーオブジェクト。complete: Observable が完了したかどうか。
function App() {
const [bar, setBar] = useState('bar');
const squid = useSquid();
const { loading, data, error, complete } = useObservable(
() => {
return squid.collection<User>('users').query().gt('foo', bar).snapshots();
},
{ initialData: [] },
[bar] // deps
);
}
オプションで、このフックは initialData オプション(デフォルトは null)および deps 配列も受け取ります。deps 配列が変更されると、現在の Observable はサブスクライブ解除され、新たなサブスクリプションが作成されます。上記の例では、クエリの where 条件が bar 変数に依存しているため、bar を依存関係として渡す必要があります。
deps が変更されるたびに、loading は新しく作成された Observable から値が発行されるまで true にリセットされます。
usePromise
usePromise フックは useObservable と類似していますが、Promise<T> を返す関数を受け取ります。このフックが直接 Promise ではなく関数を受け取る理由は、コンポーネントがマウントされるまで Promise の実行を開始しないようにするためです。
loading: Promise が解決または拒否されたかどうか。data: Promise により解決されたデータ。error: Promise が拒否された場合のエラーオブジェクト。
function App() {
const [bar, setBar] = useState('bar');
const squid = useSquid();
const { loading, data, error } = usePromise(
() => {
return squid.collection<User>('users').query().gt('foo', bar).snapshot();
},
{ initialData: [] },
[bar] // deps
);
}
このフックはまた、initialData オプション(デフォルトは null)および deps 配列を受け取ることができます。deps が変更されるたびに、進行中の Promise の結果は無視され、新しい Promise が作成されます。上記の例では、bar 変数が変更されるたびに新しい Promise が作成されます。
Feature Hooks
上記で提供されるフックに加えて、Squid React SDK は一般的な Squid のユースケースを簡素化するためのいくつかのフックも提供しています。
useAiChat
useAiChat フックは Squid AI Agents をラップして、質問の送信やチャット履歴へのアクセスを容易にします。フックは以下のように使用できます:
const { chat, history, data, loading, complete, error } = useAiChat('agent-id');
返される内容は以下の通りです:
- chat: AI エージェントへのプロンプト(文字列)を受け取る関数。
- history: メッセージの配列。各メッセージは
id、message、およびtype(aiまたはuser)を持ち、AI エージェントからの現在の応答を含みます。 - data: 現在の応答(チャット進行中の場合)。
- loading: 現在、プロンプトに対する応答待ちかどうか。
- complete: 現在の応答が完了しているかどうか。
- error: 現在のプロンプトに対してエラーが返された場合に設定されます。
const Chat = () => {
const [value, setValue] = useState('');
const { history, chat, complete } = useAiChat('agent-id');
const handleClick = () => {
chat(value);
};
return (
<>
<input onChange={(e) => setValue(e.target.value)} value={value} />
<button onClick={handleClick} disabled={!complete}>
Chat
</button>
{history.map(({ id, message, type }) => (
<span key={id}>
{type}: {message}
</span>
))}
</>
);
};