メインコンテンツまでスキップ

React SDK

Squid を React と統合するためのライブラリです。

SDK バージョン

機能

  • Squid Client の collections、documents、queries にアクセスするための Hooks。
  • React コンポーネント内のどこからでも Squid Client にアクセスできる Provider。

はじめに

要件

この SDK は React 16.11 以上が必要です。

インストール

NPM を使用して Squid React SDK をインストールします:

npm install @squidcloud/react

Squid の設定

  1. Squid Console に移動し、Create application をクリックして Application を作成します。

  2. 新しく作成した Application の overview タブから Application ID をコピーします。

  3. 次の 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 ファイルを使用している場合は、appIdregion に任意の envars を設定してください:

// main.tsx

<SquidContextProvider
options={{
appId: process.env.SQUID_CLOUD_APP_ID,
region: process.env.SQUID_CLOUD_REGION,
}}
>

Hooks

アプリケーションを SquidContextProvider でラップすると、アプリ内から Squid インスタンスにアクセスできるようになります。このインスタンスを直接参照するには、useSquid hook を使用します。

function App() {
const squid = useSquid();

const foo = () => {
squid.executeFunction('foo');
};

return <button onClick={foo}>Foo</button>;
}

ただし、collections、queries、documents へのアクセスを提供する追加の hooks もあります。

useCollection

useCollection hook は squid.collection(...) のラッパーです。squid の参照がなくても collection にアクセスできます。collection を取得したら、それを使って query を作成したり document を管理したりできます。

const collection = useCollection<User>('users');

const query = collection.query().eq('name', 'John Doe');
const doc = collection.doc('user-id');

useQuery

query を作成したら、useQuery hook を使って実行し、必要に応じて結果を subscribe できます。

この hook は次のプロパティを含むオブジェクトを返します:

  • loading: query からデータが返ってきたかどうか。
  • data: 配列としての query 結果。hook に渡す query の種類に応じて、document references、document data、join query results などになります。
  • error: query 実行中にエラーが発生した場合の error オブジェクト。
function App() {
const collection = useCollection<User>('users');

/**
* docs の一覧はクライアントにストリーミングされ、
* 最新の状態に保たれます。
*/
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 の場合、query の初期データは取得されますが、変更はストリーミングされません。

また、この hook はオプションで initialData を受け取ることができ、最初の結果が読み込まれるまでそれが返されます。

usePagination

usePagination hook は query 結果をページネーションするために使用します。ページネーションを扱うためのインターフェースを提供し、変更に合わせてデータを最新状態に保ちます。Squid のページネーションの詳細は、pagination documentation を参照してください。

この hook は次のプロパティを含むオブジェクトを返します:

  • loading: 現在データが読み込み中、またはページネーション中かどうか。
  • data: 配列としてのページネーション結果。hook に渡す query の種類に応じて、document references、document data、join query results などになります。
  • hasNext: 現在のページの後に、さらに結果があるかどうかを示す boolean。
  • hasPrev: 現在のページの前に、さらに結果があるかどうかを示す boolean。
  • next: 次のページの結果を読み込む関数(hasNext が true の場合のみ有効)。
  • prev: 前のページの結果を読み込む関数(hasPrev が true の場合のみ有効)。
function App() {
const collection = useCollection<User>('users');

/**
* users の一覧をページネーションします。
* docs の一覧はクライアントにストリーミングされ、最新の状態に保たれます。
*/
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 件であることが保証されます。

ページネーションを使用するには、query で sortBy を指定する必要があります。

また、この hook はオプションで deps 配列も受け取れます。deps 配列が変化すると、新しいページネーション query が作成されます。

useDoc

useDoc hook は似た機能を提供しますが、query への subscribe の代わりに、特定の document の更新を subscribe します。

この hook は次のプロパティを含むオブジェクトを返します:

  • loading: document query からデータが返ってきたかどうか。
  • data: document データ。データを受信していない場合、または document が削除された場合は undefined になることがあります。
  • error: document の query 中にエラーが発生した場合の error オブジェクト。
// App.tsx

function App() {
const collection = useCollection<User>('users');
const doc = collection.doc('user-id');

/**
* doc の変更はクライアントにストリーミングされ、
* 最新の状態に保たれます。
*/
const { data } = useDoc(doc);

return <span>{data.foo}</span>;
}

useDocs

useDocs hook は複数の document reference に対する更新を提供します。

この hook は次のプロパティを含むオブジェクトを返します:

  • loading: すべて の document query からデータが返ってきたかどうか。
  • data: document データの配列。配列の要素は、データを受信していない場合、または document が削除された場合に undefined になることがあります。
  • error: いずれかの document の query 中にエラーが発生した場合の error オブジェクト。
// App.tsx

function App() {
const collection = useCollection<User>('users');
const docs = [collection.doc('my-id-1'), collection.doc('my-id-2')];

/**
* documents の変更はクライアントにストリーミングされ、
* 最新の状態に保たれます。
*/
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 は usePromiseuseObservable hooks を公開しています。これらの hooks により、squid インスタンス上の非同期関数を React コンポーネント内で直接利用できます。

useObservable

useObservable hook は Observable<T> を返す関数を受け取り、observable を subscribe してコンポーネント内で更新を受け取れるようにします。次のプロパティを含むオブジェクトを返します:

  • loading: observable から値を受け取ったかどうか。
  • data: observable から受け取った最新のデータ。
  • error: observable がエラーに遭遇した場合の error オブジェクト。
  • 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
);
}

この hook はオプションで initialData(デフォルトは null)と deps 配列も受け取れます。deps 配列が変化すると、現在の observable は unsubscribe され、新しい subscription が作成されます。上の例では、query の where 条件が bar 変数に依存していることが分かります。bar が変化したときに query が適切に更新されるよう、依存関係として渡す必要があります。

deps が変化するたびに、新しく作成された observable から値が emit されるまで loading は true にリセットされます。

usePromise

usePromise hook は useObservable に似ていますが、Promise<T> を返す関数を受け取ります。promise を直接ではなく関数として受け取る理由は、コンポーネントが mount されるまで promise の実行が開始されないようにするためです。

  • loading: promise が resolve または reject されたかどうか。
  • data: promise によって resolve されたデータ。
  • error: promise が reject された場合の error オブジェクト。
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
);
}

この hook は initialData オプション(デフォルトは null)と deps 配列も受け取れます。deps が変化するたびに、進行中の promise の結果は無視され、新しい promise が作成されます。上の例では、bar 変数が変化するたびに新しい promise が作成されます。

Feature Hooks

上記の hooks に加えて、Squid React SDK は、一般的な Squid のユースケースを簡単にするために設計された hooks も提供しています。

useAiChat

useAiChat hook は Squid AI Agents をラップし、質問の送信やチャット履歴へのアクセスを簡単にします。hook は次のように使用できます:

const { chat, history, data, loading, complete, error } = useAiChat('agent-id');

そして次を返します:

  • chat: AI agent への prompt(文字列)を受け取る関数。
  • history: メッセージの配列。メッセージは idmessagetypeai または user)を持ち、AI agent からのアクティブなレスポンスも含みます。
  • data: 現在のレスポンス(チャット進行中の場合)。
  • loading: 現在の prompt に対するレスポンス待ちかどうか。
  • complete: 現在のレスポンスが完了したかどうか。
  • error -> 現在の prompt に対してエラーが返された場合に設定されます。
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>
))}
</>
);
};