Mirror: The highly customizable and versatile GraphQL client with which you add on features like normalized caching as you grow.

chore(next): update readme (#3178)

authored by

Jovi De Croock and committed by
GitHub
f892e099 ff5d7397

+2 -254
+2 -254
packages/next-urql/README.md
··· 1 - <div align="center"> 2 - <img src="../../docs/assets/next-logo.png" alt="Next.js" height="200" width="200"> 3 - <img src="../../packages/site/src/assets/sidebar-badge.svg" alt="urql" height="200" width="200"> 4 - <br /> 5 - <a href="https://npmjs.com/package/next-urql"> 6 - <img alt="NPM Version" src="https://img.shields.io/npm/v/next-urql.svg" /> 7 - </a> 8 - </div> 9 - 10 1 ## `next-urql` 11 2 12 3 A set of convenience utilities for using `urql` with Next.js. 13 4 14 - ### Motivation 15 - 16 - Using GraphQL with server-side rendering in React is a challenging problem. Currently, React has no support for `Suspense` for data fetching on the server. To get around this, a prepass step can be used to walk the tree (or a subsection of the tree) of your React application and suspend when it encounters thrown `Promise`s. For more information, check out [`react-ssr-prepass`](https://github.com/FormidableLabs/react-ssr-prepass). 17 - 18 - `next-urql` handles integrating this prepass step for you, such that your Next.js application using `urql` will prefetch your GraphQL queries on the server before sending down markup to the Client. 19 - 20 - ### Installation 21 - 22 - Install `next-urql` along with its `peerDependencies`. 23 - 24 - ```sh 25 - yarn add next-urql react-is urql graphql 26 - # or 27 - npm install --save next-urql react-is urql graphql 28 - ``` 29 - 30 - `react-is` helps to support server-side `Suspense` with `react-ssr-prepass`. This assumes you have followed the basic installation steps for `urql` [here](https://github.com/urql-graphql/urql#installation). 31 - 32 - Note that if you are using Next before v9.4 you'll need to polyfill fetch, this can be 33 - done through [`isomorphic-unfetch`](https://www.npmjs.com/package/isomorphic-unfetch). 34 - 35 - ### Usage 36 - 37 - To use `next-urql`, first `import` the `withUrqlClient` higher order component. 38 - 39 - ```javascript 40 - import { withUrqlClient } from 'next-urql'; 41 - ``` 42 - 43 - Then, for any page in your `pages` directory for which you want to prefetch GraphQL queries, wrap the page in `withUrqlClient`. For example, let's say you have an `index.js` page that renders two components that make GraphQL requests using `urql`, `PokemonList` and `PokemonTypes`. To run their queries initially on the server-side you'd do something like the following: 44 - 45 - ```javascript 46 - import React from 'react'; 47 - import Head from 'next/head'; 48 - import { withUrqlClient } from 'next-urql'; 49 - 50 - import PokemonList from '../components/pokemon_list'; 51 - import PokemonTypes from '../components/pokemon_types'; 52 - 53 - const Root = () => ( 54 - <div> 55 - <Head> 56 - <title>Root</title> 57 - <link rel="icon" href="/static/favicon.ico" /> 58 - </Head> 59 - 60 - <PokemonList /> 61 - <PokemonTypes /> 62 - </div> 63 - ); 64 - 65 - export default withUrqlClient(() => ({ url: 'https://graphql-pokemon.now.sh' }))(Root); 66 - ``` 67 - 68 - Read more below in the [API](#API) section to learn more about the arguments that can be passed to `withUrqlClient`. 69 - 70 - #### Integration with `_app.js` 71 - 72 - Next allows you to override the root of your application using a special page called [`_app.js`](https://nextjs.org/docs#custom-app). If you want to have all GraphQL requests in your application fetched on the server-side, you _could_ wrap the component exported by `_app.js` in `withUrqlClient`. However, be aware that this will opt you out of [automatic static optimization](https://nextjs.org/docs#automatic-static-optimization) for your entire application. In general, it's recommended practice to only use `withUrqlClient` on the pages that have GraphQL operations in their component tree. Read more in the [Caveats](#Caveats) section. Check out our example for using `next-urql` with `_app.js` [here](./examples/2-with-_app.js/README.md). 73 - 74 - ### API 75 - 76 - `next-urql` exposes a single higher order component, `withUrqlClient`. This HoC accepts two arguments: 77 - 78 - #### `clientOptions` (Required) 79 - 80 - The `clientOptions` argument is required. It represents all of the options you want to enable on your `urql` Client instance. It has the following union type: 81 - 82 - ```typescript 83 - type NextUrqlClientConfig = (ssrExchange: SSRExchange, ctx?: PartialNextContext) => ClientOptions; 84 - ``` 85 - 86 - The `ClientOptions` `interface` comes from `urql` itself and has the following type: 87 - 88 - ```typescript 89 - interface ClientOptions { 90 - /** The GraphQL endpoint your application is using. */ 91 - url: string; 92 - /** Any additional options to pass to fetch. */ 93 - fetchOptions?: RequestInit | (() => RequestInit); 94 - /** An alternative fetch implementation. */ 95 - fetch?: typeof fetch; 96 - /** The exchanges used by the Client. */ 97 - exchanges?: Exchange[]; 98 - /** A flag to enable suspense on the server. next-urql handles this for you. */ 99 - suspense?: boolean; 100 - /** The default request policy for requests. */ 101 - requestPolicy?: RequestPolicy; 102 - /** Use HTTP GET for queries. */ 103 - preferGetMethod?: boolean; 104 - /** Mask __typename from results. */ 105 - maskTypename?: boolean; 106 - } 107 - ``` 108 - 109 - You can create a client by passing a function which receives the `ssrExchange` and Next's context object, `ctx`, as arguments and returns `urql`'s Client options. This is helpful if you need to access some part of Next's context to instantiate your Client options. **Note: `ctx` is _only_ available on the initial server-side render and _not_ on client-side navigation**. This is necessary to allow for different Client configurations between server and client. 110 - 111 - ```typescript 112 - withUrqlClient((_ssrExchange, ctx) => ({ 113 - url: 'http://localhost:3000', 114 - fetchOptions: { 115 - headers: { 116 - Authorization: ctx 117 - ? `Bearer ${ctx?.req?.headers?.Authorization ?? ''}` 118 - : localStorage.getItem('token') ?? '', 119 - }, 120 - }, 121 - })); 122 - ``` 123 - 124 - In client-side SPAs using `urql`, you typically configure the Client yourself and pass it as the `value` prop to `urql`'s context `Provider`. `withUrqlClient` handles setting all of this up for you under the hood. By default, you'll be opted into server-side `Suspense` and have the necessary `exchanges` set up for you, including the [`ssrExchange`](https://formidable.com/open-source/urql/docs/api/#ssrexchange-exchange-factory). 125 - 126 - ### Resetting the client instance 127 - 128 - In rare scenario's you possibly will have to reset the client instance (reset all cache, ...), this is an uncommon scenario 129 - and we consider it "unsafe" so evaluate this carefully for yourself. 130 - 131 - When this does seem like the appropriate solution any component wrapped with `withUrqlClient` will receive the `resetUrqlClient` 132 - property, when invoked this will create a new top-level client and reset all prior operations. 133 - 134 - #### `exchanges` 135 - 136 - When you're using `withUrqlClient` and you don't return an `exchanges` property we'll assume you wanted the default exchanges, these contain: `dedupExchange`, `cacheExchange`, `ssrExchange` (the one you received as a first argument) and the `fetchExchange`. 137 - 138 - When you yourself want to pass exchanges don't forget to include the `ssrExchange` you received as the first argument. 139 - 140 - #### `withUrqlClientOptions` 141 - 142 - The second argument for `withUrqlClient` is an options object, this contains one `boolean` property named `ssr`, you can use this to tell 143 - `withUrqlClient` that the wrapped component does not use `getInitialProps` but the children of this wrapped component do. This opts you into 144 - `ssr` for these children. 145 - 146 - ### Different Client configurations on the client and the server 147 - 148 - There are use cases where you may need different configurations for your `urql` Client on the client-side and the server-side; for example, you may want to interact with one GraphQL endpoint on the server-side and another on the client-side. `next-urql` supports this as of v0.3.0. We recommend using `typeof window === 'undefined'` or a `process.browser` check. 149 - 150 - ```typescript 151 - withUrqlClient({ 152 - url: 153 - typeof window === 'undefined' 154 - ? 'https://my-server-graphql-api.com/graphql' 155 - : 'https://my-client-graphql-api.com/graphql', 156 - }); 157 - ``` 158 - 159 - If you want more customization of your Client instance to modify requests on specific routes, for instance, consider using a custom exchange. You can find an example of that [here](/examples/3-with-custom-exchange/README.md). 160 - 161 - ### Accessing the `urql` Client inside a Page component's `getInitialProps` method 162 - 163 - There are use cases where you may want to access the `urql` Client instance inside your Page component's `getInitialProps` method. To support this, we actually attach the `urql` Client instance to the `ctx` object passed to your Page's `getInitialProps` method. You can access it like so: 164 - 165 - ```typescript 166 - import { NextUrqlPageContext } from 'next-urql'; 167 - 168 - const Page = () => { 169 - return <main />; 170 - }; 171 - 172 - Page.getInitialProps = async (ctx: NextUrqlPageContext) => { 173 - // Do something with the urql Client instance! 174 - let client = ctx.urqlClient; 175 - 176 - return { 177 - ...props, 178 - }; 179 - }; 180 - ``` 181 - 182 - ### Usage with ReasonML 183 - 184 - While there are no official bindings for using `next-urql` with ReasonML, porting `next-urql` to Reason is not too difficult. Moreover, having your own bindings means you can select only the pieces you need from the library. Here's an example of how you could bind `next-urql` if you only needed access to the non-functional `clientOptions` API, and only wanted to pass a `url` and `fetchOptions`. This assumes BuckleScript 7 to take advantage of records compiling into plain JS objects and assumes usage of [`bs-fetch`](https://github.com/reasonml-community/bs-fetch). 185 - 186 - ```reason 187 - type clientOptions = { 188 - url: string, 189 - fetchOptions: Fetch.requestInit 190 - }; 191 - 192 - [@bs.module "next-urql"] 193 - external withUrqlClient: 194 - (. clientOptions) => 195 - (. React.component('props)) => React.component('props) = 196 - "withUrqlClient"; 197 - ``` 198 - 199 - Which can then be used like so: 200 - 201 - ```reason 202 - let headers = Fetch.HeadersInit.make({ "Content-Type": "application/json" }); 203 - let client = { 204 - url: "https://mygraphqlapi.com/graphql", 205 - fetchOptions: Fetch.RequestInit.make(~headers, ~method_=POST, ()) 206 - }; 207 - 208 - [@react.component] 209 - let make = () => { 210 - <h1>"Heck yeah, next-urql with Reason!"->React.string</h1> 211 - }; 212 - 213 - let default = (withUrqlClient(. clientOptions))(. make); 214 - ``` 215 - 216 - The great part about writing thin bindings like this is that they are zero cost – in fact, the above bindings get totally compiled away by BuckleScript, so you get the full benefits of type safety with absolutely zero runtime cost! 217 - 218 - ### Restricting Data Fetching to the Server 219 - 220 - If you want to use a `Client` in Next.js' newer methods like `getServerSideProps` you may use the `initUrqlClient` function to create a client on the fly. This will need to be done per request. 221 - 222 - ```javascript 223 - import { initUrqlClient } from 'next-urql'; 224 - 225 - export const getServerSideProps = async ctx => { 226 - const client = initUrqlClient( 227 - { 228 - url: '/graphql', 229 - }, 230 - false /* set to false to disable suspense */ 231 - ); 232 - 233 - const result = await client.query(QUERY, {}).toPromise(); 234 - 235 - return { 236 - props: { data: result.data }, 237 - }; 238 - }; 239 - ``` 240 - 241 - The first argument passed to the `initUrqlClient` function is the same object that we'd normally pass to `createClient`. 242 - The second argument is a `boolean` flag indicating whether or not to enable `suspense`; typically, we'd disable it for manual usage. 243 - 244 - ### Examples 245 - 246 - You can see simple example projects using `next-urql` in the `examples` directory or on [CodeSandbox](https://codesandbox.io/s/next-urql-pokedex-oqj3x). 247 - 248 - ### Caveats 249 - 250 - Using `withUrqlClient` on a page that has `getInitialProps` will opt that component and it's children into a prepass that does a first pass of all queries, when that 251 - component has children using `getInitialProps` but that component itself is not and you want to opt in to this behavior you'll have to set the second argument of 252 - `withUrqlClient`, this means `withUrqlClient(() => clientOptions, { ssr:true })`. 253 - This measure is available so we can support `getStaticProps`, ... 254 - 255 - When you are using `getStaticProps`, `getServerSideProps`, or `getStaticPaths`, you should opt-out of `Suspense` by setting the `neverSuspend` option to `true` in your `withUrqlClient` configuration. 256 - your `withUrqlClient`. 257 - During the prepass of your component tree `next-urql` can't know how these functions will alter the props passed to your page component. This injection 258 - could change the `variables` used in your `useQuery`. This will lead to error being thrown during the subsequent `toString` pass, which isn't supported in React 16. 5 + More documentation is available at https://urql.dev/goto/docs/advanced/server-side-rendering/#nextjs 6 + Examples can be found at https://github.com/urql-graphql/urql/tree/main/examples/with-next