React SDK
React SDK
SquidとReactを統合するためのライブラリ。
Features
- Squid Clientのcollections、documents、queriesにアクセスするためのHooks。
- 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をコピーします。
- 
Reactアプリケーションに以下のproviderを追加します: 
// 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 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を取得すれば、そのcollectionを使用してqueriesを作成したりdocumentsを管理することができます。
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: クエリ結果の配列。これは、document references、document data、join query resultsなど、hookに渡されるqueryのタイプによって異なります。
- 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 hookは、クエリ結果のページネーションに使用されます。ページネーションを処理し、データを変更に合わせて最新の状態に保つためのインターフェースを提供します。Squidのページネーションの詳細については、pagination documentation をご覧ください。
このhookは以下のプロパティを含むオブジェクトを返します:
- loading: 現在データが読み込まれている、またはページネーション中かどうか。
- data: ページネーションされた結果の配列。これは、document references、document data、join query resultsなど、hookに渡されるクエリのタイプによって異なります。
- hasNext: 現在のページの後にさらに結果が利用可能かどうかを示すboolean。
- hasPrev: 現在のページの前にさらに結果が利用可能かどうかを示すboolean。
- 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 hookは類似の機能を提供しますが、クエリの購読の代わりに特定のdocumentのアップデートを購読します。
このhookは以下のプロパティを含むオブジェクトを返します:
- loading: document queryからデータが返されたかどうか。
- data: document data。データが受信されていなかったり、documentが削除された場合はundefinedになります。
- error: documentのクエリ中にエラーが発生した場合のエラーオブジェクト。
// 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 hookは複数のdocument referenceのアップデートを提供します。
このhookは以下のプロパティを含むオブジェクトを返します:
- loading: すべてのdocumentクエリでデータが返されたかどうか。
- data: document dataの配列。各要素は、データが受信されていなかったり、documentが削除された場合undefinedになる可能性があります。
- error: いずれかのdocumentクエリの実行中にエラーが発生した場合のエラーオブジェクト。
// 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 hooksを公開しています。これらのhooksを使用すると、Reactコンポーネント内でsquidインスタンス上の非同期関数を直接利用できます。
useObservable
useObservable hookは、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が変更されるたびに、新しく作成されたobservableから値が発行されるまでloadingはtrueにリセットされます。
usePromise
usePromise hookはuseObservableと類似していますが、Promise<T>を返す関数を受け取ります。hookが直接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
  );
}
このhookはまた、initialDataオプション(デフォルトはnull)とdeps配列を受け取ることができます。depsが変更されるたびに、進行中のpromiseの結果は無視され、新しいpromiseが作成されます。上記の例では、bar変数が変更されるたびに新しいpromiseが作成されます。
Feature Hooks
上記のhooksに加えて、Squid React SDKは一般的なSquidの使用ケースを簡素化するために設計されたhooksも提供しています。
useAiChatbot
useAiChatbot hookは、AI Chatbotをラップし、質問の送信やチャット履歴へのアクセスを容易にします。以下のように使用できます:
const { chat, history, data, loading, complete, error } = useAiChatbot('integration-id', 'profile-id');
そして、以下のものを返します:
- chat: AIエージェントへのプロンプト(文字列)を受け取る関数。
- history: メッセージの配列。各メッセージは- id、- message、および- type(- aiまたは- user)を持ち、AIエージェントからのアクティブなレスポンスを含みます。
- data: 現在のレスポンス(チャットが進行中の場合)。
- loading: 現在のプロンプトに対するレスポンスを待機中かどうか。
- complete: 現在のレスポンスが完了しているかどうか。
- error: 現在のプロンプトに対してエラーが返された場合に設定されます。
const Chat = () => {
  const [value, setValue] = useState('');
  const { history, chat, complete } = useAiChatbot('integration-id', 'profile-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>
      ))}
    </>
  );
};