From 658d327036f9a5264872f3f32ae1c0b7276f487c Mon Sep 17 00:00:00 2001 From: Lynn Yu Date: Tue, 17 Dec 2024 18:08:06 -0800 Subject: [PATCH] deletes unused files in refetching folder Reviewed By: jbonta, itamark Differential Revision: D66559327 fbshipit-source-id: 81ccfca5c34702ad1242cbf72326f4540527759e --- .../list-data/refetching-connections.md | 210 ------------------ ...efetching-fragments-with-different-data.md | 171 -------------- .../refetching/refreshing-fragments.md | 191 ---------------- 3 files changed, 572 deletions(-) delete mode 100644 website/docs/guided-tour/list-data/refetching-connections.md delete mode 100644 website/docs/guided-tour/refetching/refetching-fragments-with-different-data.md delete mode 100644 website/docs/guided-tour/refetching/refreshing-fragments.md diff --git a/website/docs/guided-tour/list-data/refetching-connections.md b/website/docs/guided-tour/list-data/refetching-connections.md deleted file mode 100644 index b30bbf7dec66f..0000000000000 --- a/website/docs/guided-tour/list-data/refetching-connections.md +++ /dev/null @@ -1,210 +0,0 @@ ---- -id: refetching-connections -title: Refetching Connections (Using and Changing Filters) -slug: /guided-tour/list-data/refetching-connections/ -description: Relay guide to refetching connections -keywords: -- pagination -- refetching -- connection -- useRefetchableFragment ---- - -import DocsRating from '@site/src/core/DocsRating'; -import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal'; -import FbRefetchingConnectionsUsingUseTransition from './fb/FbRefetchingConnectionsUsingUseTransition.md'; - -Often times when querying for a list of data, you can provide different values in the query which serve as filters that change the result set, or sort it differently. - -Some examples of this are: - -* Building a search typeahead, where the list of results is a list filtered by the search term entered by the user. -* Changing the ordering mode of the list comments currently displayed for a post, which could produce a completely different set of comments from the server. -* Changing the way News Feed is ranked and sorted. - - -Specifically, in GraphQL, connection fields can accept arguments to sort or filter the set of queried results: - -```graphql -fragment UserFragment on User { - name - friends(order_by: DATE_ADDED, search_term: "Alice", first: 10) { - edges { - node { - name - age - } - } - } -} -``` - - -In Relay, we can pass those arguments as usual using GraphQL [variables](../../rendering/variables/) - -```js -type Props = { - userRef: FriendsListComponent_user$key, -}; - -function FriendsListComponent(props: Props) { - const userRef = props.userRef; - - const {data, ...} = usePaginationFragment( - graphql` - fragment FriendsListComponent_user on User { - name - friends( - order_by: $orderBy, - search_term: $searchTerm, - after: $cursor, - first: $count, - ) @connection(key: "FriendsListComponent_user_friends_connection") { - edges { - node { - name - age - } - } - } - } - `, - userRef, - ); - - return (...); -} -``` - - -When paginating, the original values for those filters will be preserved: - -```js -type Props = { - userRef: FriendsListComponent_user$key, -}; - -function FriendsListComponent(props: Props) { - const userRef = props.userRef; - - const {data, loadNext} = usePaginationFragment( - graphql` - fragment FriendsListComponent_user on User { - name - friends(order_by: $orderBy, search_term: $searchTerm) - @connection(key: "FriendsListComponent_user_friends_connection") { - edges { - node { - name - age - } - } - } - } - `, - userRef, - ); - - return ( - <> -

Friends of {data.name}:

- {...} - - {/* - Loading the next items will use the original order_by and search_term - values used for the initial query - */ } - - - ); -} -``` -* Note that calling `loadNext` will use the original `order_by` and `search_term` values used for the initial query. During pagination, these value won't (*and shouldn't*) change. - -If we want to refetch the connection with *different* variables, we can use the `refetch` function provided by `usePaginationFragment`, similarly to how we do so when [Refetching Fragments with Different Data](../../refetching/refetching-fragments-with-different-data/): - - - - - - - -```js -/** - * FriendsListComponent.react.js - */ -import type {FriendsListComponent_user$key} from 'FriendsListComponent_user.graphql'; - -const React = require('React'); -const {useState, useEffect} = require('React'); - -const {graphql, usePaginationFragment} = require('react-relay'); - - -type Props = { - searchTerm?: string, - user: FriendsListComponent_user$key, -}; - -function FriendsListComponent(props: Props) { - const searchTerm = props.searchTerm; - const {data, loadNext, refetch} = usePaginationFragment( - graphql` - fragment FriendsListComponent_user on User { - name - friends( - order_by: $orderBy, - search_term: $searchTerm, - after: $cursor, - first: $count, - ) @connection(key: "FriendsListComponent_user_friends_connection") { - edges { - node { - name - age - } - } - } - } - `, - props.user, - ); - - useEffect(() => { - // When the searchTerm provided via props changes, refetch the connection - // with the new searchTerm - refetch({first: 10, search_term: searchTerm}, {fetchPolicy: 'store-or-network'}); - }, [searchTerm]) - - return ( - <> -

Friends of {data.name}:

- - {/* When the button is clicked, refetch the connection but sorted differently */} - - - ... - - - ); -} -``` - -Let's distill what's going on here: - -* Calling `refetch` and passing a new set of variables will fetch the fragment again *with the newly provided variables*. The variables you need to provide are a subset of the variables that the generated query expects; the generated query will require an `id`, if the type of the fragment has an `id` field, and any other variables that are transitively referenced in your fragment. - * In our case, we need to pass the count we want to fetch as the `first` variable, and we can pass different values for our filters, like `orderBy` or `searchTerm`. -* This will re-render your component and may cause it to suspend (as explained in [Loading States with Suspense](../../rendering/loading-states/)) if it needs to send and wait for a network request. If `refetch` causes the component to suspend, you'll need to make sure that there's a `Suspense` boundary wrapping this component from above. -* Conceptually, when we call refetch, we're fetching the connection *from scratch*. It other words, we're fetching it again from the *beginning* and *"resetting"* our pagination state. For example, if we fetch the connection with a different `search_term`, our pagination information for the previous `search_term` no longer makes sense, since we're essentially paginating over a new list of items. - -
- - - - - diff --git a/website/docs/guided-tour/refetching/refetching-fragments-with-different-data.md b/website/docs/guided-tour/refetching/refetching-fragments-with-different-data.md deleted file mode 100644 index 81e954561a270..0000000000000 --- a/website/docs/guided-tour/refetching/refetching-fragments-with-different-data.md +++ /dev/null @@ -1,171 +0,0 @@ ---- -id: refetching-fragments-with-different-data -title: Refetching Fragments with Different Data -slug: /guided-tour/refetching/refetching-fragments-with-different-data/ -description: Relay guide to refetching fragments with different data -keywords: -- refetching -- fragment ---- - -import DocsRating from '@site/src/core/DocsRating'; -import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal'; -import FbRefetchingFragments from './fb/FbRefetchingFragments.md'; -import FbAvoidSuspenseCaution from './fb/FbAvoidSuspenseCaution.md'; -import OssAvoidSuspenseNote from './OssAvoidSuspenseNote.md'; - -When referring to **"refetching a fragment"**, we mean fetching a *different* version of the data than the one was originally rendered by the fragment. For example, this might be to change a currently selected item, to render a different list of items than the one being shown, or more generally to transition the currently rendered content to show new or different content. - -Conceptually, this means fetching and rendering the currently rendered fragment again, but under a new query with *different variables*; or in other words, rendering the fragment under a new query root. Remember that *fragments can't be fetched by themselves: they need to be part of a query,* so we can't just "fetch" the fragment again by itself. - -## Using `useRefetchableFragment` - -To do so, we can also use the [`useRefetchableFragment`](../../../api-reference/use-refetchable-fragment/) Hook in combination with the `@refetchable` directive, which will automatically generate a query to refetch the fragment under, and which we can fetch using the `refetch` function: - - - - - - - -```js -import type {CommentBody_comment$key} from 'CommentBody_comment.graphql'; - -type Props = { - comment: CommentBody_comment$key, -}; - -function CommentBody(props: Props) { - const [data, refetch] = useRefetchableFragment( - graphql` - fragment CommentBody_comment on Comment - # @refetchable makes it so Relay autogenerates a query for - # fetching this fragment - @refetchable(queryName: "CommentBodyRefetchQuery") { - body(lang: $lang) { - text - } - } - `, - props.comment, - ); - - const refetchTranslation = () => { - // We call refetch with new variables, - // which will refetch the @refetchable query with the - // new variables and update this component with the - // latest fetched data. - refetch({lang: 'SPANISH'}); - }; - - return ( - <> -

{data.body?.text}

- - - ); -} -``` - -Let's distill what's happening in this example: - -* `useRefetchableFragment` behaves similarly to [`useFragment`](../../../api-reference/use-fragment/) (see the [Fragments](../../rendering/fragments/) section), but with a few additions: - * It expects a fragment that is annotated with the `@refetchable` directive. Note that `@refetchable` directive can only be added to fragments that are "refetchable", that is, on fragments that are on `Viewer`, on `Query`, on any type that implements `Node` (i.e. a type that has an `id` field), or on a [`@fetchable`](https://fb.workplace.com/groups/graphql.fyi/permalink/1539541276187011/) type. -* It returns a `refetch` function, which is already Flow-typed to expect the query variables that the generated query expects. -* It takes two Flow type parameters: the type of the generated query (in our case `CommentBodyRefetchQuery`), and a second type which can always be inferred, so you only need to pass underscore (`_`). -* We're calling the `refetch` function with 2 main inputs: - * The first argument is the set of variables to fetch the fragment with. In this case, calling `refetch` and passing a new set of variables will fetch the fragment again *with the newly provided variables*. The variables you need to provide are a subset of the variables that the `@refetchable` query expects; the query will require an `id`, if the type of the fragment has an `id` field, and any other variables that are transitively referenced in your fragment. - * In this case we're passing the current comment `id` and a new value for the `translationType` variable to fetch the translated comment body. - * We are not passing a second options argument in this case, which means that we will use the default `fetchPolicy` of `'store-or-network'`, which will skip the network request if the new data for that fragment is already cached (as we covered in [Reusing Cached Data For Render](../../reusing-cached-data/)). -* Calling `refetch` will re-render the component and may cause `useRefetchableFragment` to suspend (as explained in [Loading States with Suspense](../../rendering/loading-states/)). This means that you'll need to make sure that there's a `Suspense` boundary wrapping this component from above in order to show a fallback loading state. - -
- -:::info -Note that this same behavior also applies to using the `refetch` function from [`usePaginationFragment`](../../../api-reference/use-pagination-fragment). -::: - -### If you need to avoid Suspense - -In some cases, you might want to avoid showing a Suspense fallback, which would hide the already rendered content. For these cases, you can use [`fetchQuery`](../../../api-reference/fetch-query/) instead, and manually keep track of a loading state: - - - - - - - - - -```js -import type {CommentBody_comment$key} from 'CommentBody_comment.graphql'; - -type Props = { - comment: CommentBody_comment$key, -}; - -function CommentBody(props: Props) { - const [data, refetch] = useRefetchableFragment( - graphql` - fragment CommentBody_comment on Comment - # @refetchable makes it so Relay autogenerates a query for - # fetching this fragment - @refetchable(queryName: "CommentBodyRefetchQuery") { - body(lang: $lang) { - text - } - } - `, - props.comment, - ); - - const [isRefetching, setIsRefreshing] = useState(false) - const refetchTranslation = () => { - if (isRefetching) { return; } - setIsRefreshing(true); - - // fetchQuery will fetch the query and write - // the data to the Relay store. This will ensure - // that when we re-render, the data is already - // cached and we don't suspend - fetchQuery(environment, AppQuery, variables) - .subscribe({ - complete: () => { - setIsRefreshing(false); - - // *After* the query has been fetched, we call - // refetch again to re-render with the updated data. - // At this point the data for the query should - // be cached, so we use the 'store-only' - // fetchPolicy to avoid suspending. - refetch({lang: 'SPANISH'}, {fetchPolicy: 'store-only'}); - } - error: () => { - setIsRefreshing(false); - } - }); - }; - - return ( - <> -

{data.body?.text}

- - - ); -} -``` - -Let's distill what's going on here: - -* When refetching, we now keep track of our own `isRefetching` loading state, since we are avoiding suspending. We can use this state to render a busy spinner or similar loading UI in our component, *without* hiding the content. -* In the event handler, we first call `fetchQuery`, which will fetch the query and write the data to the local Relay store. When the `fetchQuery` network request completes, we call `refetch` so that we render the updated data, similar to the previous example. -* At this point, when `refetch` is called, the data for the fragment should already be cached in the local Relay store, so we use `fetchPolicy` of `'store-only'` to avoid suspending and only read the already cached data. - - diff --git a/website/docs/guided-tour/refetching/refreshing-fragments.md b/website/docs/guided-tour/refetching/refreshing-fragments.md deleted file mode 100644 index 937af7feb3495..0000000000000 --- a/website/docs/guided-tour/refetching/refreshing-fragments.md +++ /dev/null @@ -1,191 +0,0 @@ ---- -id: refreshing-fragments -title: Refreshing Fragments -slug: /guided-tour/refetching/refreshing-fragments/ -description: Relay guide to refreshing fragments -keywords: -- refreshing -- fragment ---- - -import DocsRating from '@site/src/core/DocsRating'; -import {OssOnly, FbInternalOnly} from 'docusaurus-plugin-internaldocs-fb/internal'; -import FbRefreshingUsingRealTimeFeatures from './fb/FbRefreshingUsingRealTimeFeatures.md'; -import FbRefreshingFragments from './fb/FbRefreshingFragments.md'; -import FbAvoidSuspenseCaution from './fb/FbAvoidSuspenseCaution.md'; -import OssAvoidSuspenseNote from './OssAvoidSuspenseNote.md'; - -When referring to **"refreshing a fragment"**, we mean fetching the *exact* same data that was originally rendered by the fragment, in order to get the most up-to-date version of that data from the server. - -## Using real-time features - - - - - - -If we want to keep our data up to date with the latest version from the server, the first thing to consider is if it appropriate to use any real-time features, which can make it easier to automatically keep the data up to date without manually refreshing the data periodically. - -One example of this is using [GraphQL Subscriptions](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/), which will require additional configuration on your server and [network layer](https://relay.dev/docs/guided-tour/updating-data/graphql-subscriptions/#configuring-the-network-layer). - - -## Using `useRefetchableFragment` - -In order to manually refresh the data for a fragment, we need a query to refetch the fragment under; remember, *fragments can't be fetched by themselves: they need to be part of a query,* so we can't just "fetch" the fragment again by itself. - -To do so, we can also use the [`useRefetchableFragment`](../../../api-reference/use-refetchable-fragment/) Hook in combination with the `@refetchable` directive, which will automatically generate a query to refetch the fragment under, and which we can fetch using the `refetch` function: - - - - - - - -```js -import type {UserComponent_user$key} from 'UserComponent_user.graphql'; - -type Props = { - user: UserComponent_user$key, -}; - -function UserComponent(props: Props) { - const [data, refetch] = useRefetchableFragment( - graphql` - fragment UserComponent_user on User - # @refetchable makes it so Relay autogenerates a query for - # fetching this fragment - @refetchable(queryName: "UserComponentRefreshQuery") { - id - name - friends { - count - } - } - `, - props.user, - ); - - const refresh = useCallback(() => { - // We call refetch with empty variables: `{}`, - // which will refetch the @refetchable query with the same - // original variables the fragment was fetched with, and update - // this component with the latest fetched data. - // The fetchPolicy ensures we always fetch from the server and skip - // the local data cache. - refetch({}, {fetchPolicy: 'network-only'}) - }), [/* ... */]; - - return ( - <> -

{data.name}

-
Friends count: {data.friends?.count}
- - - ); -} -``` - -Let's distill what's happening in this example: - -* `useRefetchableFragment` behaves similarly to [`useFragment`](../../../api-reference/use-fragment/) (see the [Fragments](../../rendering/fragments/) section), but with a few additions: - * It expects a fragment that is annotated with the `@refetchable` directive. Note that `@refetchable` directive can only be added to fragments that are "refetchable", that is, on fragments that are on `Viewer`, on `Query`, on any type that implements `Node` (i.e. a type that has an `id` field). -* It returns a `refetch` function, which is already Flow-typed to expect the query variables that the generated query expects -* It takes two Flow type parameters: the type of the generated query (in our case `UserComponentRefreshQuery`), and a second type which can always be inferred, so you only need to pass underscore (`_`). -* We're calling the `refetch` function with 2 main inputs: - * The first argument is the set of variables to fetch the fragment with. In this case, calling `refetch` and passing an empty set of variables will fetch the fragment again *with the exact same variables the fragment was originally fetched with,* which is what we want for a refresh. - * In the second argument we are passing a `fetchPolicy` of `'network-only'` to ensure that we always fetch from the network and skip the local data cache. -* Calling `refetch` will re-render the component and cause `useRefetchableFragment` to suspend (as explained in [Loading States with Suspense](../../rendering/loading-states/)), since a network request will be required due to the `fetchPolicy` we are using. This means that you'll need to make sure that there's a `Suspense` boundary wrapping this component from above in order to show a fallback loading state. - -
- -:::info -Note that this same behavior also applies to using the `refetch` function from [`usePaginationFragment`](../../../api-reference/use-pagination-fragment). -::: - -### If you need to avoid Suspense - -In some cases, you might want to avoid showing a Suspense fallback, which would hide the already rendered content. For these cases, you can use [`fetchQuery`](../../../api-reference/fetch-query/) instead, and manually keep track of a loading state: - - - - - - - - - -```js -import type {UserComponent_user$key} from 'UserComponent_user.graphql'; - -type Props = { - user: UserComponent_user$key, -}; - -function UserComponent(props: Props) { - const [data, refetch] = useRefetchableFragment( - graphql` - fragment UserComponent_user on User - # @refetchable makes it so Relay autogenerates a query for - # fetching this fragment - @refetchable(queryName: "UserComponentRefreshQuery") { - id - name - friends { - count - } - } - `, - props.user, - ); - - const [isRefreshing, setIsRefreshing] = useState(false); - const refresh = useCallback(() => { - if (isRefreshing) { return; } - setIsRefreshing(true); - - // fetchQuery will fetch the query and write - // the data to the Relay store. This will ensure - // that when we re-render, the data is already - // cached and we don't suspend - fetchQuery(environment, AppQuery, variables) - .subscribe({ - complete: () => { - setIsRefreshing(false); - - // *After* the query has been fetched, we call - // refetch again to re-render with the updated data. - // At this point the data for the query should - // be cached, so we use the 'store-only' - // fetchPolicy to avoid suspending. - refetch({}, {fetchPolicy: 'store-only'}); - }, - error: () => { - setIsRefreshing(false); - } - }); - }, [/* ... */]); - - return ( - <> -

{data.name}

-
Friends count: {data.friends?.count}
- - - ); -} -``` - -Let's distill what's going on here: - -* When refreshing, we now keep track of our own `isRefreshing` loading state, since we are avoiding suspending. We can use this state to render a busy spinner or similar loading UI in our component, *without* hiding the content. -* In the event handler, we first call `fetchQuery`, which will fetch the query and write the data to the local Relay store. When the `fetchQuery` network request completes, we call `refetch` so that we render the updated data, similar to the previous example. -* At this point, when `refetch` is called, the data for the fragment should already be cached in the local Relay store, so we use `fetchPolicy` of `'store-only'` to avoid suspending and only read the already cached data. - -