From ee6cbfc1fa9781a76be0d9aaa036b9b59bbfefa5 Mon Sep 17 00:00:00 2001 From: Stephen Barlow Date: Fri, 10 Jul 2020 19:18:51 -0700 Subject: [PATCH 1/4] Edits to AC intro and getting started --- docs/source/get-started.mdx | 51 +++++++++++++++++-------------- docs/source/index.mdx | 60 +++++++++++++++++++++---------------- 2 files changed, 63 insertions(+), 48 deletions(-) diff --git a/docs/source/get-started.mdx b/docs/source/get-started.mdx index e6a22a27b12..3dbf5c8068d 100644 --- a/docs/source/get-started.mdx +++ b/docs/source/get-started.mdx @@ -3,32 +3,30 @@ title: Get started description: Set up Apollo Client in your React app --- -Out of the box Apollo Client includes packages that we think are essential for building an Apollo app, like our in-memory cache, local state management, error handling, and a React based view layer. +Hello! This short tutorial gets you up and running with Apollo Client. -> This tutorial walks you through installing and configuring Apollo Client -> for your React app. If you're just getting started with GraphQL or the Apollo -> platform, we recommend first completing the [full-stack tutorial](https://www.apollographql.com/docs/tutorial/introduction/). +> For a more complete introduction to the entire Apollo platform, we recommend first completing the [full-stack tutorial](https://www.apollographql.com/docs/tutorial/introduction/). ## Installation -First, let's install the Apollo Client and GraphQL packages: +First, let's install the packages we need: ```bash npm install @apollo/client graphql ``` -- `@apollo/client`: Contains everything you need to set up Apollo Client -- `graphql`: Parses your GraphQL queries +- `@apollo/client`: This single package contains virtually everything you need to set up Apollo Client. It includes the in-memory cache, local state management, error handling, and a React-based view layer. +- `graphql`: This package provides logic for parsing GraphQL queries. > If you'd like to walk through this tutorial yourself, we recommend either running a new React project locally with [Create React App](https://create-react-app.dev/) or creating a new React sandbox on [CodeSandbox](https://codesandbox.io/). For reference, we will be using [this CodeSandbox](https://codesandbox.io/s/practical-snyder-48p1r2roz4) as our GraphQL server for our sample app, which pulls exchange rate data from the Coinbase API. If you'd like to skip ahead and see the app we're about to build, you can [view it on CodeSandbox](https://codesandbox.io/s/get-started-coinbase-client-73r10). ## Create a client -Great, now that you have all the dependencies you need, let's create your Apollo Client. The only thing you need to get started is the endpoint for your GraphQL server. +Now that we have all the dependencies we need, let's initialize an `ApolloClient` instance. You'll need to provide it the URL of a running GraphQL server, such as [this CodeSandbox instance](https://codesandbox.io/s/practical-snyder-48p1r2roz4). -In our `index.js` file, let's import `ApolloClient` from `@apollo/client` and add the endpoint for our GraphQL server to the `uri` property of the client config object. +In `index.js`, let's import `ApolloClient` from `@apollo/client` and provide our GraphQL server's URL as the `uri` property of the constructor's configuration object: -```js +```js:title=index.js import { ApolloClient, InMemoryCache } from '@apollo/client'; const client = new ApolloClient({ @@ -37,12 +35,14 @@ const client = new ApolloClient({ }); ``` -That's it! Now your client is ready to start fetching data. Before we show how to use Apollo Client with React, let's try sending a query with plain JavaScript first. In the same `index.js` file, try calling `client.query()`. Remember to first import the `gql` function for parsing your query string into a query document. +That's it! Our `client` is ready to start fetching data. Now, before we start using Apollo Client with React, let's first try sending a query with plain JavaScript. -```js +In the same `index.js` file, call `client.query()` with the query string shown below. You'll need to import the `gql` function to parse the query string into a query document. + +```js:title=index.js import { gql } from '@apollo/client'; -... +// const client = ... client .query({ @@ -57,13 +57,17 @@ client .then(result => console.log(result)); ``` -Open up your console and inspect the result object. You should see a `data` property with `rates` attached, along with some other properties like `loading` and `networkStatus`. While you don't need React or another front-end framework just to fetch data with Apollo Client, our view layer integrations make it easier to bind your queries to your UI and reactively update your components with data. Let's learn how to use Apollo Client with React so we can start building query components. +Run this code, open your console, and inspect the result object. You should see a `data` property with `rates` attached, along with some other properties like `loading` and `networkStatus`. + +Although executing GraphQL operations like this can be useful, Apollo Client really shines when it's integrated with a view layer like react. You can bind queries to your UI and update it automatically as new data is fetched. + +Let's look at how that works! ## Connect your client to React -To connect Apollo Client to React, you will need to use the `ApolloProvider` component. The `ApolloProvider` is similar to React's [`Context.Provider`](https://reactjs.org/docs/context.html#contextprovider). It wraps your React app and places the client on the context, which allows you to access it from anywhere in your component tree. +To connect Apollo Client to React with the `ApolloProvider` component. The `ApolloProvider` is similar to React's [`Context.Provider`](https://reactjs.org/docs/context.html#contextprovider). It wraps your React app and places the client on the context, which enables you to access it from anywhere in your component tree. -In `index.js`, let's wrap our React app with an `ApolloProvider`. We suggest putting the `ApolloProvider` somewhere high in your app, above any places where you need to access GraphQL data. For example, it could be outside of your root route component if you're using React Router. +In `index.js`, let's wrap our React app with an `ApolloProvider`. We suggest putting the `ApolloProvider` somewhere high in your app, above any component that might need to access GraphQL data. For example, it could be outside of your root route component if you're using React Router. ```jsx import React from 'react'; @@ -86,11 +90,14 @@ render(, document.getElementById('root')); ## Request data -Once your `ApolloProvider` is hooked up, you're ready to start requesting data with the `useQuery` hook! `useQuery` is a hook that leverages the [Hooks API](https://reactjs.org/docs/hooks-intro.html) to share GraphQL data with your UI. +Once your `ApolloProvider` is hooked up, you're ready to start requesting data with `useQuery`. `useQuery` is a React hook that use the [Hooks API](https://reactjs.org/docs/hooks-intro.html) to share GraphQL data with your UI. + +First, pass your GraphQL query (wrapped in the `gql` function) to the `useQuery` hook. When your component renders and the `useQuery` hook runs, a result object is returned that contains `loading`, `error`, and `data` properties: -First, pass your GraphQL query wrapped in the `gql` function into the `useQuery` hook. When your component renders and the `useQuery` hook runs, a result object will be returned containing `loading`, `error`, and `data` properties. Apollo Client tracks error and loading state for you, which will be reflected in the `loading` and `error` properties. Once the result of your query comes back, it will be attached to the `data` property. +* Apollo Client tracks error and loading state for you, which are reflected in the `loading` and `error` properties. +* When the result of your query comes back, it's attached to the `data` property. -Let's create an `ExchangeRates` component in `index.js` to see the `useQuery` hook in action! +Let's create an `ExchangeRates` component in `index.js` to see the `useQuery` hook in action: ```jsx import { useQuery, gql } from '@apollo/client'; @@ -120,13 +127,13 @@ function ExchangeRates() { } ``` -Congrats, you just made your first `useQuery` based component! 🎉 If you render your `ExchangeRates` component within your `App` component from the previous example, you'll first see a loading indicator and then data on the page once it's ready. Apollo Client automatically caches this data when it comes back from the server, so you won't see a loading indicator if you run the same query twice. +Congrats, you just made your first `useQuery`-based component! 🎉 If you render your `ExchangeRates` component within your `App` component from the previous example, you'll first see a loading indicator on the page, followed by data when it's ready. Apollo Client automatically caches this data when it comes back from the server, so you won't see a loading indicator if you run the same query again. -If you'd like to play around with the app we just built, you can [view it on CodeSandbox](https://codesandbox.io/s/get-started-coinbase-client-73r10). Don't stop there! Try building more components that leverage `useQuery` and experimenting with the concepts you just learned. +To play around with the app we just built, [check it out on CodeSandbox](https://codesandbox.io/s/get-started-coinbase-client-73r10). But don't stop there! Try building more components that use `useQuery`, and experiment with the concepts you just learned. ## Next steps -Now that you've learned how to fetch data with Apollo Client, you're ready to dive deeper into creating more complex queries and mutations. After this section, we recommend moving onto: +Now that you've learned how to fetch data with Apollo Client, you're ready to dive deeper into creating more complex queries and mutations. After this section, we recommend moving on to: - [Queries](data/queries/): Learn how to fetch queries with arguments and dive deeper into configuration options. For a full list of options, check out the API reference for `useQuery`. - [Mutations](data/mutations/): Learn how to update data with mutations and when you'll need to update the Apollo cache. For a full list of options, check out the API reference for `useMutation` components. diff --git a/docs/source/index.mdx b/docs/source/index.mdx index 6bdbe10969a..e95e77634ae 100644 --- a/docs/source/index.mdx +++ b/docs/source/index.mdx @@ -1,46 +1,54 @@ --- -title: Introduction -description: What is Apollo Client? +title: Introduction to Apollo Client +sidebar_title: Introduction --- +import { Button } from '@apollo/space-kit/Button'; +import { Link } from 'gatsby'; +import { colors } from 'gatsby-theme-apollo-core'; + > **Apollo Client 3.0 is officially released.** If you are currently using a previous version of Apollo Client, we recommend [migrating](../migrating/apollo-client-3-migration/). > > For documentation of previous versions, use the version switcher in the upper left. -**Apollo Client** is a complete state management library for JavaScript apps. Simply write a GraphQL query, and Apollo Client will take care of requesting and caching your data, as well as updating your UI. - -Fetching data with Apollo Client guides you to structure your code in a predictable, declarative way consistent with modern React best practices. With Apollo, you can build high-quality features faster without the hassle of writing data plumbing boilerplate. +**Apollo Client** is a comprehensive state management library for JavaScript that enables you to manage both local and remote data with GraphQL. Use it to fetch, cache, and modify application data, all while automatically updating your UI. -## Features +Apollo Client helps helps you structure code in an economical, predictable, and declarative way that's consistent with modern development practices. The core `@apollo/client` library provides built-in integration with React, and the larger Apollo community maintains [integrations for other popular view layers](#community-integrations). -- **Declarative data fetching:** Write a query and receive data without manually tracking loading states -- **Excellent developer experience:** Enjoy helpful tooling for TypeScript, Chrome DevTools, and VS Code -- **Designed for modern React:** Take advantage of the latest React features, such as hooks -- **Incrementally adoptable:** Drop Apollo into any JavaScript app seamlessly -- **Universally compatible:** Use any build setup and any GraphQL API -- **Community driven:** Share knowledge with thousands of developers, thanks to our active open source community +
+ +
-## Get started - -Follow the [quick start tutorial](get-started/) to start fetching data in minutes. For a longer end-to-end example that includes pagination, local state management, and building a graph API, check out the [official Apollo tutorial](https://www.apollographql.com/docs/tutorial/introduction/). +## Features -## Explore Apollo Client +- **Declarative data fetching:** Write a query and receive data without manually tracking loading states. +- **Excellent developer experience:** Enjoy helpful tooling for TypeScript, Chrome DevTools, and VS Code. +- **Designed for modern React:** Take advantage of the latest React features, such as hooks. +- **Incrementally adoptable:** Drop Apollo into any JavaScript app seamlessly. +- **Universally compatible:** Use any build setup and any GraphQL API. +- **Community driven:** Share knowledge with thousands of developers, thanks to our active open source community. -The Apollo Client docs are structured into the following sections. +## Explore the docs -1. **Fetching data:** Start here to learn how to fetch data, update data, and manage local state with Apollo Client. -2. **Caching:** Learn the ins and outs of Apollo Client's caching system. -3. **Development & testing:** TypeScript, testing and development tooling details. -4. **Performance:** Advanced Apollo Client capabilities to help with application performance. -5. **Integrations:** Apollo Client view layer integrations. -6. **Networking:** Basic and advanced network communication approaches. -7. **API:** Full API details for Apollo Client, its React APIs, and additional packages +After you [get started](./get-started/), check out the full Apollo Client docs, organized into the following sections on the left: -We recommend starting with [Fetching data](./data/queries/) first, before moving on to advanced topics. +* **Fetching:** Execute queries and other GraphQL operations on your server. **Definitely read [Queries](./data/queries/) if you haven't yet.** +* **Caching:** Query your cache directly and make local-only modifications to your data. +* **Local State:** Manage both local and remotely fetched state with a single API. +* **Development & testing:** Learn about Apollo Client's language and tooling support. +* **Performance:** Take advantage of advanced features to optimize performance and user experience. +* **Integrations:** Explore support for view layers besides React. +* **Networking:** Learn how Apollo Client communicates over the network by default, along with how to customize this behavior. +* **API:** Consult the complete API reference for Apollo Client, its React APIs, and additional packages. ## Community integrations -This site's documentation focuses on React, but Apollo Client supports many other platforms: +This site's documentation focuses on React, but Apollo Client supports many other libraries and languages: - JavaScript - [Angular](https://www.apollographql.com/docs/angular) From ec41f460541541240957664f8e14eb22f0e95fc7 Mon Sep 17 00:00:00 2001 From: Stephen Barlow Date: Fri, 10 Jul 2020 19:20:56 -0700 Subject: [PATCH 2/4] Add missing dependency for ink --- docs/package-lock.json | 119 ++++++++++++++++++++++++++++++++++++++++- docs/package.json | 1 + 2 files changed, 118 insertions(+), 2 deletions(-) diff --git a/docs/package-lock.json b/docs/package-lock.json index 2cc2a01f7a9..9358a2a28bc 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -2986,7 +2986,7 @@ "babel-plugin-dynamic-import-node": "^2.3.3", "babel-plugin-macros": "^2.8.0", "babel-plugin-transform-react-remove-prop-types": "^0.4.24", - "gatsby-core-utils": "^1.3.8" + "gatsby-core-utils": "^1.3.11" }, "dependencies": { "gatsby-core-utils": { @@ -7621,7 +7621,7 @@ "webpack-hot-middleware": "^2.25.0", "webpack-merge": "^4.2.2", "webpack-stats-plugin": "^0.3.1", - "xstate": "^4.10.0", + "xstate": "^4.11.0", "yaml-loader": "^0.6.0" }, "dependencies": { @@ -10442,6 +10442,121 @@ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" }, + "ink": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/ink/-/ink-2.7.1.tgz", + "integrity": "sha512-s7lJuQDJEdjqtaIWhp3KYHl6WV3J04U9zoQ6wVc+Xoa06XM27SXUY57qC5DO46xkF0CfgXMKkKNcgvSu/SAEpA==", + "requires": { + "ansi-escapes": "^4.2.1", + "arrify": "^2.0.1", + "auto-bind": "^4.0.0", + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-truncate": "^2.1.0", + "is-ci": "^2.0.0", + "lodash.throttle": "^4.1.1", + "log-update": "^3.0.0", + "prop-types": "^15.6.2", + "react-reconciler": "^0.24.0", + "scheduler": "^0.18.0", + "signal-exit": "^3.0.2", + "slice-ansi": "^3.0.0", + "string-length": "^3.1.0", + "widest-line": "^3.1.0", + "wrap-ansi": "^6.2.0", + "yoga-layout-prebuilt": "^1.9.3" + }, + "dependencies": { + "ansi-escapes": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "requires": { + "type-fest": "^0.11.0" + } + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==" + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "react-reconciler": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.24.0.tgz", + "integrity": "sha512-gAGnwWkf+NOTig9oOowqid9O0HjTDC+XVGBCAmJYYJ2A2cN/O4gDdIuuUQjv8A4v6GDwVfJkagpBBLW5OW9HSw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.18.0" + } + }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==" + } + } + }, "ink-box": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/ink-box/-/ink-box-1.0.0.tgz", diff --git a/docs/package.json b/docs/package.json index 0f68e4ecda0..80287b5e742 100644 --- a/docs/package.json +++ b/docs/package.json @@ -9,6 +9,7 @@ "dependencies": { "gatsby": "2.23.20", "gatsby-theme-apollo-docs": "4.3.4", + "ink": "^2.7.1", "react": "16.12.0", "react-dom": "16.12.0" }, From 329fe31b5383c5c76fcde96c640d8baebc785f82 Mon Sep 17 00:00:00 2001 From: Stephen Barlow Date: Sun, 12 Jul 2020 20:25:57 -0700 Subject: [PATCH 3/4] Fix broken links --- docs/source/api/react/hoc.mdx | 4 +- docs/source/features/caching.md | 262 -------------------- docs/source/local-state/local-resolvers.mdx | 4 +- 3 files changed, 4 insertions(+), 266 deletions(-) delete mode 100644 docs/source/features/caching.md diff --git a/docs/source/api/react/hoc.mdx b/docs/source/api/react/hoc.mdx index 16efc9e9511..1efb2625f12 100644 --- a/docs/source/api/react/hoc.mdx +++ b/docs/source/api/react/hoc.mdx @@ -58,7 +58,7 @@ const TodoAppWithData = withTodoAppQuery(TodoApp); export default TodoAppWithData; ``` -The `graphql()` function will only be able to provide access to your GraphQL data if there is a [``](./hooks/#apolloprovider) component higher up in your tree to provide an [`ApolloClient`](../core/) instance that will be used to fetch your data. +The `graphql()` function will only be able to provide access to your GraphQL data if there is a [``](./hooks/#apolloprovider) component higher up in your tree to provide an [`ApolloClient`](../core/ApolloClient/) instance that will be used to fetch your data. The behavior of your component enhanced with the `graphql()` function will be different depending on if your GraphQL operation is a [query](../../data/queries/), a [mutation](../../data/mutations/), or a [subscription](../../data/subscriptions/). Go to the appropriate API documentation for more information about the functionality and available options for each type. @@ -1071,7 +1071,7 @@ export default graphql( import { withApollo } from '@apollo/react-hoc'; ``` -A simple enhancer which provides direct access to your [`ApolloClient`](../core/) instance. This is useful if you want to do custom logic with Apollo. Such as calling one-off queries. By calling this function with the component you want to enhance, `withApollo()` will create a new component which passes in an instance of `ApolloClient` as a `client` prop. +A simple enhancer which provides direct access to your [`ApolloClient`](../core/ApolloClient/) instance. This is useful if you want to do custom logic with Apollo. Such as calling one-off queries. By calling this function with the component you want to enhance, `withApollo()` will create a new component which passes in an instance of `ApolloClient` as a `client` prop. If you are wondering when to use `withApollo()` and when to use [`graphql()`](#graphqlquery-configcomponent) the answer is that most of the time you will want to use `graphql()`. `graphql()` provides many of the advanced features you need to work with your GraphQL data. You should only use `withApollo()` if you want the GraphQL client without any of the other features. diff --git a/docs/source/features/caching.md b/docs/source/features/caching.md deleted file mode 100644 index 5042573bc9d..00000000000 --- a/docs/source/features/caching.md +++ /dev/null @@ -1,262 +0,0 @@ ---- -title: Direct Cache Access -order: 109 -description: Read and write functions for fine-grained cache access. ---- - -Apollo Client normalizes all of your data so that if any data you previously fetched from your GraphQL server is updated in a later data fetch from your server then your data will be updated with the latest truth from your server. - -This normalization process is constantly happening behind the scenes when you call `watchQuery` or use Apollo Client's React view integration, but this process is often not enough to describe the updates to your data model as the result of a mutation. For example, if you wanted to add an item to the end of an array fetched by one of your queries. You also might want to read data from the normalized Apollo Client store at a specific id without making another GraphQL server fetch. - -To interact directly with your data in the Apollo Client store you may use the methods `readQuery`, `readFragment`, `writeQuery`, and `writeFragment` that are accessible from the `ApolloClient` class. This article will teach you how to use these methods to control your data. - -All of the methods we will discuss can be called from the `ApolloClient` class. Any code demonstration in this article will assume that we have already initialized an instance of `ApolloClient` and assigned it to the `client`, and that we have imported the `gql` function. Like so: - -```js -import { ApolloClient, gql } from '@apollo/client'; - -const client = new ApolloClient({ ... }); -``` - -## `readQuery` - -The `readQuery` method is very similar to the [`query` method on `ApolloClient`](../api/core/#ApolloClient.query) except that `readQuery` will _never_ make a request to your GraphQL server. The `query` method, on the other hand, may send a request to your server if the appropriate data is not in your cache whereas `readQuery` will throw an error if the data is not in your cache. `readQuery` will _always_ read from the cache. You can use `readQuery` by giving it a GraphQL query like so: - -```js -const { todo } = client.readQuery({ - query: gql` - query ReadTodo { - todo(id: 5) { - id - text - completed - } - } - `, -}); -``` - -If all of the data needed to fulfill this read is in Apollo Client’s normalized data cache then a data object will be returned in the shape of the query you wanted to read. If not all of the data needed to fulfill this read is in Apollo Client’s cache then an error will be thrown instead, so make sure to only read data that you know you have! - -You can also pass variables into `readQuery`. - -```js -const { todo } = client.readQuery({ - query: gql` - query ReadTodo($id: Int!) { - todo(id: $id) { - id - text - completed - } - } - `, - variables: { - id: 5, - }, -}); -``` - -**Resources:** - -- [`ApolloClient#query` API documentation](../api/core/#ApolloClient.query) -- [`ApolloClient#readQuery` API documentation](../api/core/#ApolloClient.readQuery) - -## `readFragment` - -This method allows you great flexibility around the data in your cache. Whereas `readQuery` only allowed you to read data from your root query type, `readFragment` allows you to read data from _any node you have queried_. This is incredibly powerful. You use this method as follows: - -```js -const todo = client.readFragment({ - id: ..., // `id` is any id that could be returned by `dataIdFromObject`. - fragment: gql` - fragment myTodo on Todo { - id - text - completed - } - `, -}); -``` - -The first argument is the id of the data you want to read from the cache. That id must be a value that was returned by the `dataIdFromObject` function you defined when initializing `ApolloClient`. So for example if you initialized `ApolloClient` like so: - -```js -const client = new ApolloClient({ - ..., - dataIdFromObject: object => object.id, -}); -``` - -…and you requested a todo before with an id of `5`, then you can read that todo out of your cache with the following: - -```js -const todo = client.readFragment({ - id: '5', - fragment: gql` - fragment myTodo on Todo { - id - text - completed - } - `, -}); -``` - -> **Note:** Most people add a `__typename` to the id in `dataIdFromObject`. If you do this then don’t forget to add the `__typename` when you are reading a fragment as well. So for example your id may be `Todo_5` and not just `5`. - -If a todo with that id does not exist in the cache you will get `null` back. If a todo of that id does exist in the cache, but that todo does not have the `text` field then an error will be thrown. - -The beauty of `readFragment` is that the todo could have come from anywhere! The todo could have been selected as a singleton (`{ todo(id: 5) { ... } }`), the todo could have come from a list of todos (`{ todos { ... } }`), or the todo could have come from a mutation (`mutation { createTodo { ... } }`). As long as at some point your GraphQL server gave you a todo with the provided id and fields `id`, `text`, and `completed` you can read it from the cache at any part of your code. - -**Resources:** - -- [`ApolloClient#readFragment` API documentation](../api/core/#ApolloClient.readFragment) - -## `writeQuery` and `writeFragment` - -Not only can you read arbitrary data from the Apollo Client cache, but you can also write any data that you would like to the cache. The methods you use to do this are `writeQuery` and `writeFragment`. They will allow you to change data in your local cache, but it is important to remember that *they will not change any data on your server*. If you reload your environment then changes made with `writeQuery` and `writeFragment` will disappear. - -These methods have the same signature as their `readQuery` and `readFragment` counterparts except they also require an additional `data` variable. So for example, if you wanted to update the `completed` flag locally for your todo with id `'5'` you could execute the following: - -```js -client.writeFragment({ - id: '5', - fragment: gql` - fragment myTodo on Todo { - completed - } - `, - data: { - completed: true, - }, -}); -``` - -Any subscriber to the Apollo Client store will instantly see this update and render new UI accordingly. - -> **Note:** Again, remember that using `writeQuery` or `writeFragment` only changes data *locally*. If you reload your environment then changes made with these methods will no longer exist. - -Or if you wanted to add a new todo to a list fetched from the server, you could use `readQuery` and `writeQuery` together. - -```js -const query = gql` - query MyTodoAppQuery { - todos { - id - text - completed - } - } -`; - -const data = client.readQuery({ query }); - -const myNewTodo = { - id: '6', - text: 'Start using Apollo Client.', - completed: false, -}; - -client.writeQuery({ - query, - data: { - todos: [...data.todos, myNewTodo], - }, -}); -``` - -**Resources:** - -- [`ApolloClient#watchQuery` API documentation](../api/core/#ApolloClient.watchQuery) -- [`ApolloClient#writeQuery` API documentation](../api/core/#ApolloClient.writeQuery) -- [`ApolloClient#writeFragment` API documentation](../api/core/#ApolloClient.writeFragment) -- [`DataProxy#writeQuery` API documentation](../api/core/#ApolloClient.writeQuery) -- [`DataProxy#writeFragment` API documentation](../api/core/#ApolloClient.writeFragment) - -## Updating the cache after a mutation - -Being able to read and write to the Apollo cache from anywhere in your application gives you a lot of power over your data. However, there is one place where we most often want to update our cached data: after a mutation. As such, Apollo Client has optimized the experience for updating your cache with the read and write methods after a mutation with the `update` function. Let us say that we have the following GraphQL mutation: - -```graphql -mutation TodoCreateMutation($text: String!) { - createTodo(text: $text) { - id - text - completed - } -} -``` - -We may also have the following GraphQL query: - -```graphql -query TodoAppQuery { - todos { - id - text - completed - } -} -``` - -At the end of our mutation we want our query to include the new todo like we had sent our `TodoAppQuery` a second time after the mutation finished without actually sending the query. To do this we can use the `update` function provided as an option of the `client.mutate` method. To update your cache with the mutation just write code that looks like: - -```js -// We assume that the GraphQL operations `TodoCreateMutation` and -// `TodoAppQuery` have already been defined using the `gql` tag. - -const text = 'Hello, world!'; - -client.mutate({ - mutation: TodoCreateMutation, - variables: { - text, - }, - update: (proxy, { data: { createTodo } }) => { - // Read the data from our cache for this query. - const data = proxy.readQuery({ query: TodoAppQuery }); - - // Add our todo from the mutation to the end. - data.todos.push(createTodo); - - // Write our data back to the cache. - proxy.writeQuery({ query: TodoAppQuery, data }); - }, -}); -``` - -The first `proxy` argument is an instance of `DataProxy` and has the same for methods that we just learned exist on the Apollo Client: `readQuery`, `readFragment`, `writeQuery`, and `writeFragment`. The reason we call them on a `proxy` object here instead of on our `client` instance is that we can easily apply optimistic updates (which we will demonstrate in a bit). The `proxy` object also provides an isolated transaction which shields you from any other mutations going on at the same time, and the `proxy` object also batches writes together until the very end. - -If you provide an `optimisticResponse` option to the mutation then the `update` function will be run twice. Once immediately after you call `client.mutate` with the data from `optimisticResponse`. After the mutation successfully executes against the server the changes made in the first call to `update` will be rolled back and `update` will be called with the *actual* data returned by the mutation and not just the optimistic response. - -Putting it all together: - -```js -const text = 'Hello, world!'; - -client.mutate({ - mutation: TodoCreateMutation, - variables: { - text, - }, - optimisticResponse: { - id: -1, // -1 is a temporary id for the optimistic response. - text, - completed: false, - }, - update: (proxy, { data: { createTodo } }) => { - const data = proxy.readQuery({ query: TodoAppQuery }); - data.todos.push(createTodo); - proxy.writeQuery({ query: TodoAppQuery, data }); - }, -}); -``` - -As you can see the `update` function on `client.mutate` provides extra change management functionality specific to the use case of a mutation while still providing you the powerful data control APIs that are available on `client`. - -The `update` function is not a good place for side-effects as it may be called multiple times. Also, you may not call any of the methods on `proxy` asynchronously. - -**Resources:** - -- [`ApolloClient#mutate` API documentation](../api/core/#ApolloClient.mutate) diff --git a/docs/source/local-state/local-resolvers.mdx b/docs/source/local-state/local-resolvers.mdx index ff1f4a7ee0b..b633b75d549 100644 --- a/docs/source/local-state/local-resolvers.mdx +++ b/docs/source/local-state/local-resolvers.mdx @@ -226,7 +226,7 @@ cache.writeQuery({ }); ``` -Sometimes you may need to [reset the store](../api/core/#ApolloClient.resetStore) in your application, when a user logs out for example. If you call `client.resetStore` anywhere in your application, you will likely want to initialize your cache again. You can do this using the `client.onResetStore` method to register a callback that will call `cache.writeQuery` again. +Sometimes you may need to [reset the store](../api/core/ApolloClient/#ApolloClient.resetStore) in your application, when a user logs out for example. If you call `client.resetStore` anywhere in your application, you will likely want to initialize your cache again. You can do this using the `client.onResetStore` method to register a callback that will call `cache.writeQuery` again. ```js import { ApolloClient, InMemoryCache } from '@apollo/client'; @@ -562,7 +562,7 @@ Pulling `@client` field values directly out of the cache isn't quite as flexible ### Working with fetch policies -Before Apollo Client executes a query, one of the first things it does is check to see which [`fetchPolicy`](../api/core/#apolloclient-functions) it has been configured to use. It does this so it knows where it should attempt to resolve the query from first, either the cache or the network. When running a query, Apollo Client treats `@client` based local resolvers just like it does remote resolvers, in that it will adhere to its defined `fetchPolicy` to know where to attempt to pull data from first. When working with local resolvers, it's important to understand how fetch policies impact the running of resolver functions, since by default local resolver functions are not run on every request. This is because the result of running a local resolver is cached with the rest of the query result, and pulled from the cache on the next request. Let's look at an example: +Before Apollo Client executes a query, one of the first things it does is check to see which [`fetchPolicy`](../api/core/ApolloClient/#apolloclient-functions) it has been configured to use. It does this so it knows where it should attempt to resolve the query from first, either the cache or the network. When running a query, Apollo Client treats `@client` based local resolvers just like it does remote resolvers, in that it will adhere to its defined `fetchPolicy` to know where to attempt to pull data from first. When working with local resolvers, it's important to understand how fetch policies impact the running of resolver functions, since by default local resolver functions are not run on every request. This is because the result of running a local resolver is cached with the rest of the query result, and pulled from the cache on the next request. Let's look at an example: ```jsx import React, { Fragment } from "react"; From e53afd96876659c940097d7c1f9f9dd8bcfcff4b Mon Sep 17 00:00:00 2001 From: Stephen Barlow Date: Sun, 12 Jul 2020 20:36:30 -0700 Subject: [PATCH 4/4] update link checking exceptions and add redirect --- docs/gatsby-config.js | 2 +- docs/static/_redirects | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/gatsby-config.js b/docs/gatsby-config.js index 309bbbc95f8..c3e79b0d106 100644 --- a/docs/gatsby-config.js +++ b/docs/gatsby-config.js @@ -19,7 +19,7 @@ module.exports = { }, checkLinksOptions: { exceptions: [ - '/api/apollo-client/', + '/api/core/ApolloClient/', '/v2.6/api/apollo-client/', '/v2.5/api/apollo-client/', '/v2.4/api/apollo-client/', diff --git a/docs/static/_redirects b/docs/static/_redirects index f3df99c60ca..42c6ee1a73d 100644 --- a/docs/static/_redirects +++ b/docs/static/_redirects @@ -3,6 +3,9 @@ # Remove 'Recompose patterns' article /docs/react/development-testing/recompose/ /docs/react/ +# Client 3.0 changes +/docs/react/api/apollo-client/ /docs/react/api/core/ApolloClient/ + # Apollo Client Information Architecture refresh # https://github.com/apollographql/apollo-client/pull/5321 /docs/react/features/error-handling/ /docs/react/data/error-handling/