{"id":15391015,"url":"https://github.com/michalkvasnicak/react-apollo-graphql","last_synced_at":"2025-04-15T21:44:44.561Z","repository":{"id":65372144,"uuid":"91798011","full_name":"michalkvasnicak/react-apollo-graphql","owner":"michalkvasnicak","description":"Get rid of decorators and use Apollo GraphQL queries and mutations in the simple and readable way.","archived":false,"fork":false,"pushed_at":"2017-08-28T09:32:53.000Z","size":190,"stargazers_count":16,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-04-24T16:10:52.384Z","etag":null,"topics":["apollo","apollo-client","component","graphql","react","react-native"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/michalkvasnicak.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-05-19T11:09:33.000Z","updated_at":"2023-03-12T09:01:26.000Z","dependencies_parsed_at":"2023-01-19T23:16:37.294Z","dependency_job_id":null,"html_url":"https://github.com/michalkvasnicak/react-apollo-graphql","commit_stats":null,"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michalkvasnicak%2Freact-apollo-graphql","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michalkvasnicak%2Freact-apollo-graphql/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michalkvasnicak%2Freact-apollo-graphql/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michalkvasnicak%2Freact-apollo-graphql/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/michalkvasnicak","download_url":"https://codeload.github.com/michalkvasnicak/react-apollo-graphql/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":233034701,"owners_count":18614890,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["apollo","apollo-client","component","graphql","react","react-native"],"created_at":"2024-10-01T15:09:36.963Z","updated_at":"2025-01-10T02:19:43.820Z","avatar_url":"https://github.com/michalkvasnicak.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# react-apollo-graphql\n\n[![npm](https://img.shields.io/npm/v/react-apollo-graphql.svg)](https://www.npmjs.com/package/react-apollo-graphql)\n[![CircleCI](https://circleci.com/gh/michalkvasnicak/react-apollo-graphql/tree/master.svg?style=svg\u0026circle-token=20c4fae1b9bd62446eec2d27c334b154c06efc9a)](https://circleci.com/gh/michalkvasnicak/react-apollo-graphql/tree/master)\n\n![gzip size](http://img.badgesize.io/https://unpkg.com/react-apollo-graphql/dist/react-apollo-graphql.min.js?compression=gzip\u0026label=gzip%20size)\n![size](http://img.badgesize.io/https://unpkg.com/react-apollo-graphql/dist/react-apollo-graphql.min.js?label=size)\n![module formats: umd, cjs, esm](https://img.shields.io/badge/module%20formats-umd%2C%20cjs%2C%20esm-green.svg)\n\nThis is opinionated replacement for `graphql` decorator from `react-apollo` package.\n\n**Under development, API can change**\n\n`npm install --save react-apollo-graphql`\n\nIt provides:\n\n* simple error handling on the component level\n* readable passing of queries' results to your component\n* typed props and render props using flow type\n* server side render\n\n## Usage\n\n### Using `\u003cApolloProvider /\u003e` from `react-apollo`\n\n```js\nimport GraphQL from 'react-apollo-graphql';\nimport ApolloClient from 'apollo-client';\nimport ApolloProvider from 'react-apollo';\n\n\u003cApolloProvider client={new ApolloClient(...)}\u003e\n  \u003cGraphQL render={(queries, mutations, props) =\u003e \u003cdiv /\u003e} /\u003e\n\u003c/ApolloProvider\u003e\n```\n\n### Passing `ApolloClient` directly\n\n```js\nimport GraphQL from 'react-apollo-graphql';\nimport ApolloClient from 'apollo-client';\n\n\u003cGraphQL client={new ApolloClient(...)} render={(queries, mutations, props) =\u003e \u003cdiv /\u003e} /\u003e\n```\n\n### Queries\n\nIn order to use define and use queries, one has to initialize them.\n\n```js\n// @flow\n\nimport type { QueryInitializerOptions } from 'react-apollo-graphql';\nimport type { ApolloClient, ObservableQuery } from 'react-apollo-graphql/lib/types';\n\nconst queries = {\n  // queryA will be resolved only once\n  queryA: (\n    client: ApolloClient,\n    props: Object\n  ): ObservableQuery\u003c{ id: number }\u003e =\u003e client.watchQuery({\n    query: gql`{ id }`,\n  }),\n  // queryB will be resolved everytime the relevant props change\n  queryB: (\n    client: ApolloClient,\n    props: Object,\n    options: QueryInitializerOptions\n  ): ObservableQuery\u003c{ name: string }\u003e =\u003e {\n    // add our function which will be called on every props change\n    options.hasVariablesChanged((currentProps, nextProps) =\u003e {\n      if (currentProps.name === nextProps.name) {\n        return false;\n      }\n\n      return { name: nextProps.name };\n    });\n\n    return client.watchQuery({\n      query: gql`query test($name: String!) { id(name: $name)}`,\n      variables: { name: props.name },\n    });\n  }\n};\n\n\u003cGraphQL\n  queries={queries}\n  render={(initializedQueries) =\u003e {\n    console.log(initializeQueries.queryA.data);\n    console.log(initializeQueries.queryA.loading);\n    console.log(initializeQueries.queryA.error);\n    console.log(initializeQueries.queryA.networkStatus);\n    console.log(initializeQueries.queryA.partial);\n  }}\n/\u003e\n```\n\n### Mutations\n\nIn order to define and use mutations, one has to provided initializers. Initializers are called on every render so you have current `props` available in the initializers.\n\n```js\n// @flow\n\nimport type { ApolloClient, QueryResult } from 'react-apollo-graphql/lib/types';\n\nconst mutations = {\n  registerUser: (\n    client: ApolloClient,\n    props: Object\n  ) =\u003e (): Promise\u003cQueryResult\u003c{ registerUser: boolean }\u003e\u003e =\u003e client.mutate({\n    mutation: gql`mutation registerUser($email: String!) { registerUser(email: $email) }`,\n    variables: {\n      email: props.email,\n    },\n  }),\n};\n\n\u003cGraphQL\n  email=\"test@test.com\"\n  mutations={mutations}\n  render={(queries, mutations, fetchers, props) =\u003e {\n    mutations.registerUser(props.email).then(\n      (data) =\u003e console.log(data.registerUser),\n      e =\u003e console.error(e),\n    );\n  }}\n/\u003e\n```\n\n### Fetchers\n\nIn order to use fetchers (queries that run only when user invokes them), user has to first initialize them. Fetchers are initialized with `client` and current `props` on each render and passed to `render()` function.\n\n```js\n// @flow\n\nimport type { QueryInitializerOptions } from 'react-apollo-graphql';\nimport type { ApolloClient, QueryResult } from 'react-apollo-graphql/lib/types';\n\nconst fetchers = {\n  // queryA will be resolved only once\n  search: (\n    client: ApolloClient,\n    props: Object\n  ) =\u003e (term: string): Promise\u003cQueryResult\u003cArray\u003c{ id: number }\u003e\u003e\u003e =\u003e client.query({\n    query: gql`query search($term: String!) { search(term: $term) { id } }`,\n    variables: { term },\n  }),\n};\n\n\u003cGraphQL\n  fetchers={fetchers}\n  text=\"text\"\n  render={(queries, mutations, fetchers, props) =\u003e {\n    fetchers.search(props.text).then(\n      (data) =\u003e console.log(data.search[0].id);\n    );\n  }}\n/\u003e\n```\n\n### Fragments\n\nIn order to use fragments (you can simulate partial results using fragments), user has to first initialize them. Fragments are initialized with `client`, previous `props` and current `props` on `componentWillMount` and every update if `props` used by given fragment have changed. If props have not changed and you don't want fragment to fetch data on every update, return `false`.\n\n```js\n// @flow\n\nimport type { QueryInitializerOptions } from 'react-apollo-graphql';\nimport type { ApolloClient, FragmentResult } from 'react-apollo-graphql/lib/types';\n\nconst fragments = {\n  // user detail will be resolved on componentWillMount and on every update if props\n  // used as variables have changed\n  userDetail: (\n    client: ApolloClient,\n    previousProps: ?Object,\n    currentProps: Object\n  ): FragmentResult\u003c{ __typename: 'User', id: number, name: string }\u003e =\u003e {\n    if (previousProps \u0026\u0026 previousProps.id === currentProps.id) {\n      return false;\n    }\n\n    return client.readFragment({\n      id: `User:${currentProps.id}`,\n      fragment: gql`fragment userDetails on User { __typename, id, name }`,\n    });\n  }\n};\n\n\u003cGraphQL\n  fragments={fragments}\n  id={10}\n  render={(queries, mutations, fetchers, fragments, props) =\u003e {\n    expect(fragments.userDetail).toEqual({\n      __typename: 'User',\n      id: 10,\n      name: 'Fero',\n    });\n  }}\n/\u003e\n```\n\n## Server side render\n\nFor server side rendering you need to:\n\n1. import helper as `import { getDataFromTree } from 'react-apollo-graphql';`\n2. instantiate your view (`const view = \u003cApp /\u003e;`)\n3. wait for all queries to be resolved `await getDataFromTree(view);`\n4. render view `ReactDOM.renderToString(view);`\n5. profit (but you have to hydrate your apollo store on the client side 😉 )\n\n### React-Router v4\n\n```js\n// example taken from react-router v4 docs\nimport { createServer } from 'http';\nimport ApolloClient from 'apollo-client';\nimport ApolloProvider from 'react-apollo';\nimport React from 'react';\nimport ReactDOMServer from 'react-dom/server';\nimport { StaticRouter } from 'react-router';\nimport { getDataFromTree } from 'react-apollo-graphql';\nimport App from './App';\n\ncreateServer(async (req, res) =\u003e {\n  const context = {};\n  const client = new ApolloClient();\n\n  const view = (\n    \u003cStaticRouter\n      location={req.url}\n      context={context}\n    \u003e\n      \u003cApolloProvider client={client}\u003e\n        \u003cApp/\u003e\n      \u003c/ApolloProvider\u003e\n    \u003c/StaticRouter\u003e\n  );\n\n  await getDataFromTree(view);\n\n  const html = ReactDOMServer.renderToString(view);\n\n  if (context.url) {\n    res.writeHead(301, {\n      Location: context.url\n    });\n    res.end();\n  } else {\n    res.write(`\n      \u003c!doctype html\u003e\n      \u003cdiv id=\"app\"\u003e${html}\u003c/div\u003e\n    `);\n    res.end();\n  }\n}).listen(3000);\n```\n\n## API\n\n### ApolloClient\n\n* apollo client is provided from `apollo-client` package. See [documentation](http://dev.apollodata.com/core/apollo-client-api.html#apollo-client).\n\n### QueryInitializerOptions\n\n```js\n// @flow\n\nexport type QueryInitializerOptions = {\n  // sets function to determine if there is a relevant change in props to compute new variables\n  // returns false if there is no change in props used for variables\n  // or returns new variables for query.setVariables()\n  hasVariablesChanged: (\n    (currentProps: Object, nextProps: Object) =\u003e boolean | { [key: string]: any },\n  ) =\u003e void,\n};\n```\n\n### `\u003cGraphQL fetchers?={Fetchers} fragments?={Fragments} queries?={Queries} mutations?={Mutations} render={RenderFunction} /\u003e`\n\n* `Fragments = { [key: string]: (client: ApolloClient, previousProps: ?Object, currentProps: Object) =\u003e FragmentResult\u003cany\u003e }`\n  * `optional` prop, object with fragments' initializer\n  * **each initializer will be initialized with Apollo client, previousProps and props passed to the initializer on each mount and update**\n  * **each initializer is update only if it does not return false**\n  * each initializer has to return `false` or result of `client.readFragment()` (this means that it has to call the [`client.readFragment() method`](http://dev.apollodata.com/core/apollo-client-api.html#ApolloClient\\.readFragment))\n* `Fetchers = { [key: string]: (client: ApolloClient, props: Object) =\u003e (...args: any) =\u003e Promise\u003cQueryResult\u003c*\u003e\u003e}`\n  * `optional` prop, object with fetchers' initializer\n  * **each initializer will be initialized with apollo client and props passed to the initializer on each render (on mount and every update)**\n  * each initializer has to return `(...args: any) =\u003e Promise\u003cQueryResult\u003c*\u003e\u003e` (this means that it has to call the [`client.query() method`](http://dev.apollodata.com/core/apollo-client-api.html#ApolloClient\\.query))\n* `Queries = { [key: string]: (client: ApolloClient, props: Object, options: QueryInitializerOptions) =\u003e ObservableQuery\u003c*\u003e }`\n  * `optional` prop, object with query initializers.\n  * **each initializer will be initialized with apollo client and props passed to initializer on component mount**\n  * each initializer has to return `ObservableQuery` (this means that it has to call the [`client.watchQuery() method`](http://dev.apollodata.com/core/apollo-client-api.html#ApolloClient\\.watchQuery))\n* `Mutations = { [key: string]: (client: ApolloClient, props: Object) =\u003e () =\u003e Promise\u003cQueryResult\u003c*\u003e\u003e}`\n  * `optional` prop, object with mutation initializers\n  * **each initializer will be initialized with apollo client and props passed to the initializer on each render (on mount and every update)**\n  * each initializer has to return `() =\u003e Promise\u003cQueryResult\u003c*\u003e\u003e` (this means that it has to call the [`client.mutate() method`](http://dev.apollodata.com/core/apollo-client-api.html#ApolloClient\\.mutate))\n* `RenderFunction = (queries: InitializedQueries, mutations: InitializedMutations, fetchers: InitializedFetchers, props: Object) =\u003e React$Element\u003cany\u003e`\n  * called on mount and updates\n  * `queries` arg: result of each query initializer passed to the `queries` prop on `\u003cGraphQL /\u003e` component will be mapped to it's result, plus additional methods like `fetchMore(), refetch(), etc` see [`client.watchQuery() method`](http://dev.apollodata.com/core/apollo-client-api.html#ApolloClient\\.watchQuery)\n  * `mutations` arg: each mutation initializer from the `mutations` prop passed to the `\u003cGraphQL /\u003e` component will be called on render and the result will be passed under the same `key` to the `mutations` arg of render function.\n  * `fetchers` arg: each fetcher initializer from the `fetchers` prop passed to the `\u003cGraphQL /\u003e` component will be called on render and the returned function will be passed under the same `key` to the `fetchers` arg of render function.\n  * `props` arg: current props passed to `\u003cGraphQL /\u003e` component\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichalkvasnicak%2Freact-apollo-graphql","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmichalkvasnicak%2Freact-apollo-graphql","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichalkvasnicak%2Freact-apollo-graphql/lists"}