ストアデータの命令的な変更
ストア内のリンクフィールドの更新に関するこのガイドも参照してください。
Relayストア内のデータは、アップデーター関数内で命令的に変更できます。
アップデーターを使用する場合
複雑なクライアント更新
ローカルデータへの変更が、ネットワークレスポンスをストアに書き込むだけでは実現できないほど複雑で、宣言的なミューテーションディレクティブでは処理できない場合は、アップデーター関数を提供することがあります。
クライアントスキーマ拡張
さらに、ネットワークレスポンスにはクライアントスキーマ拡張で定義されたフィールドのデータが含まれていないため、アップデーターを使用してクライアントスキーマ拡張で定義されたデータを初期化することができます。
他のAPIの使用
最後に、ノードの無効化、ノードの削除、特定のフィールドにあるすべてのコネクションの検索など、アップデーターを使用しないと実現できないことがあります。
複数のオプティミスティックレスポンスが特定のストア値を変更する場合
2つのオプティミスティックレスポンスが特定の値に影響を与え、最初のオプティミスティックレスポンスがロールバックされた場合、2つ目のレスポンスは適用されたままになります。
たとえば、2つのオプティミスティックレスポンスがそれぞれストーリーのいいねカウントを1つずつ増やし、最初のオプティミスティックレスポンスがロールバックされた場合、2つ目のオプティミスティックレスポンスは適用されたままになります。ただし、再計算は**されず**、いいねカウントの値は2つ増えたままになります。
アップデーターを**使用しない**場合
他の副作用をトリガーする場合
他の副作用をトリガーするには、`onCompleted`コールバックを使用する必要があります。 `onCompleted`コールバックは1回だけ呼び出されることが保証されていますが、アップデーターとオプティミスティックアップデーターは繰り返し呼び出される可能性があります。
さまざまなタイプのアップデーター関数
`useMutation` APIと`commitMutation` APIは、`optimisticUpdater`フィールドと`updater`フィールドを含むことができる設定オブジェクトを受け入れます。 `requestSubscription` APIと`useSubscription` APIは、`updater`フィールドを含むことができる設定オブジェクトを受け入れます。
さらに、アップデーター関数を受け入れる別のAPI(`commitLocalUpdate`)があります。これは、ローカルデータを変更するための他のAPIセクションで説明します。
オプティミスティックアップデーターとアップデーター
ミューテーションには、オプティミスティックアップデーターと通常のアップデーターの両方を含めることができます。オプティミスティックアップデーターは、ミューテーションがトリガーされたときに実行されます。そのミューテーションが完了またはエラーになった場合、オプティミスティック更新はロールバックされます。
通常のアップデーターは、ミューテーションが正常に完了したときに実行されます。
例
ミューテーションアップデーターで新しく作成されたFeedbackオブジェクトの`is_new_comment`フィールド(スキーマ拡張で定義されている)を`true`に設定する例を作成してみましょう。
# Feedback.graphql
extend type Feedback {
is_new_comment: Boolean
}
// CreateFeedback.js
import type {Environment} from 'react-relay';
import type {
FeedbackCreateData,
CreateFeedbackMutation,
CreateFeedbackMutation$data,
} from 'CreateFeedbackMutation.graphql';
const {commitMutation, graphql} = require('react-relay');
const {ConnectionHandler} = require('relay-runtime');
function commitCreateFeedbackMutation(
environment: Environment,
input: FeedbackCreateData,
) {
return commitMutation<FeedbackCreateData>(environment, {
mutation: graphql`
mutation CreateFeedbackMutation($input: FeedbackCreateData!) {
feedback_create(input: $input) {
feedback {
id
# Step 1: in the mutation response, spread an updatable fragment (defined below).
# This updatable fragment will select the fields that we want to update on this
# particular feedback object.
...CreateFeedback_updatable_feedback
}
}
}
`,
variables: {input},
// Step 2: define an updater
updater: (store: RecordSourceSelectorProxy, response: ?CreateCommentMutation$data) => {
// Step 3: Access and nullcheck the feedback object.
// Note that this could also have been achieved with the @required directive.
const feedbackRef = response?.feedback_create?.feedback;
if (feedbackRef == null) {
return;
}
// Step 3: call store.readUpdatableFragment
const {updatableData} = store.readUpdatableFragment(
// Step 4: Pass it a fragment literal, where the fragment contains the @updatable directive.
// This fragment selects the fields that you wish to update on the feedback object.
// In step 1, we spread this fragment in the query response.
graphql`
fragment CreateFeedback_updatable_feedback on Feedback @updatable {
is_new_comment
}
`,
// Step 5: Pass the fragment reference.
feedbackRef
);
// Step 6: Mutate the updatableData object!
updatableData.is_new_comment = true;
},
});
}
module.exports = {commit: commitCreateFeedbackMutation};
ここで何が起こっているのかを詳しく見てみましょう。
- `updater`は2つのパラメーターを受け取ります。`RecordSourceSelectorProxy`と、ミューテーションレスポンスの読み出し結果であるオプションのオブジェクトです。
- この2番目の引数のタイプは、生成されたミューテーションファイルからインポートされた`$data`タイプのnull許容バージョンです。
- 2番目の引数には、ミューテーション引数によって直接選択されたデータのみが含まれています。つまり、スプレッドフラグメントによってのみ選択されたフィールドは含まれません。
- この`updater`は、ミューテーションレスポンスがストアに書き込まれた後に実行されます。
- このアップデーターの例では、3つのことを行います
- まず、ミューテーションレスポンスで更新可能なフラグメントをスプレッドします。
- 次に、`readUpdatableFragment`を呼び出すことによって、このフラグメントによって選択されたフィールドを読み出します。これは、更新可能なプロキシオブジェクトを返します。
- 3番目に、この更新可能なプロキシのフィールドを更新します。
- このアップデーターが完了すると、記録された更新がストアに書き込まれ、影響を受けるすべてのコンポーネントが再レンダリングされます。
例2: ユーザーインタラクションに応じたデータの更新
ユーザーインタラクションに応答してストアデータを更新するという一般的なケースを考えてみましょう。クリックハンドラーで、`is_selected`フィールドを切り替えます。このフィールドは、クライアントスキーマ拡張のUsersで定義されています。
# User.graphql
extend type User {
is_selected: Boolean
}
// UserSelectToggle.react.js
import type {RecordSourceSelectorProxy} from 'react-relay';
import type {UserSelectToggle_viewer$key} from 'UserSelectToggle_viewer.graphql';
const {useRelayEnvironment, commitLocalUpdate} = require('react-relay');
function UserSelectToggle({ userId, viewerRef }: {
userId: string,
viewerRef: UserSelectToggle_viewer$key,
}) {
const viewer = useFragment(graphql`
fragment UserSelectToggle_viewer on Viewer {
user(user_id: $user_id) {
id
name
is_selected
...UserSelectToggle_updatable_user
}
}
`, viewerRef);
const environment = useRelayEnvironment();
return <button
onClick={() => {
commitLocalUpdate(
environment,
(store: RecordSourceSelectorProxy) => {
const userRef = viewer.user;
if (userRef == null) {
return;
}
const {updatableData} = store.readUpdatableFragment(
graphql`
fragment UserSelectToggle_updatable_user on User @updatable {
is_selected
}
`,
userRef
);
updatableData.is_selected = !viewer?.user?.is_selected;
}
);
}}
>
{viewer?.user?.is_selected ? 'Deselect' : 'Select'} {viewer?.user?.name}
</button>
}
ここで何が起こっているのかを詳しく見てみましょう。
- クリックハンドラーで、Relay環境とアップデーター関数を受け取る`commitLocalUpdate`を呼び出します。 **前の例とは異なり、このアップデーターは2番目のパラメーターを受け取りません**。これは、関連付けられたネットワークペイロードがないためです。
- このアップデーター関数では、`store.readUpdatableFragment`を呼び出すことによって更新可能なプロキシオブジェクトにアクセスし、`is_selected`フィールドを切り替えます。
- `readUpdatableFragment`を呼び出した前の例と同様に、これは`readUpdatableQuery` APIを使用して書き直すことができます。
この例は、`environment.commitPayload` APIを使用して書き直すことができますが、タイプセーフではなくなります。
代替API: `readUpdatableQuery`。
前の例では、更新可能なフラグメントを使用して、更新するフィールドを持つレコードにアクセスしました。これは、更新可能なクエリを使用して行うこともできます。
ルート(つまり、タイプが`Query`であるオブジェクト)から変更するレコードへのパスがわかっている場合は、`readUpdatableQuery` APIを使用してこれを実現できます。
たとえば、イベントに応じてビューアの`name`フィールドを次のように設定できます
// NameUpdater.react.js
function NameUpdater({ queryRef }: {
queryRef: NameUpdater_viewer$key,
}) {
const environment = useRelayEnvironment();
const data = useFragment(
graphql`
fragment NameUpdater_viewer on Viewer {
name
}
`,
queryRef
);
const [newName, setNewName] = useState(data?.viewer?.name);
const onSubmit = () => {
commitLocalUpdate(environment, store => {
const {updatableData} = store.readUpdatableQuery(
graphql`
query NameUpdaterUpdateQuery @updatable {
viewer {
name
}
}
`,
{}
);
const viewer = updatableData.viewer;
if (viewer != null) {
viewer.name = newName;
}
});
};
// etc
}
- この特定の例は、`readUpdatableFragment`を使用して書き直すことができます。ただし、いくつかの理由で`readUpdatableQuery`の方が適している場合があります
- `commitLocalUpdate`の呼び出しがコンポーネントに明確に関連付けられていない場合など、フラグメント参照にすぐにアクセスできない場合。
- 変更するレコードの**親レコード**(この例では`Query`)を選択するフラグメントにすぐにアクセスできない場合。Relayの既知のタイプホールにより、**更新可能なフラグメントをトップレベルでスプレッドすることはできません。**
- 更新可能なフラグメントで変数を使用する場合。現在、更新可能なフラグメントは、クエリに渡された変数を再利用します。これは、たとえば、フラグメントローカル変数を持つ更新可能なフラグメントがあり、`readUpdatableFragment`を複数回呼び出し、毎回異なる変数を渡すことができないことを意味します。
このページは役に立ちましたか?
いくつかの簡単な質問に答えることで、サイトの改善にご協力ください いくつかの簡単な質問に答える.