All Projects → michalkvasnicak → react-apollo-graphql

michalkvasnicak / react-apollo-graphql

Licence: MIT license
Get rid of decorators and use Apollo GraphQL queries and mutations in the simple and readable way.

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to react-apollo-graphql

GitHunt-Polymer
An example of a client-side app built with Polymer and Apollo Client.
Stars: ✭ 13 (-18.75%)
Mutual labels:  apollo, apollo-client
apollo-fragment
Use Apollo Link State to connect components to GraphQL fragments in the Apollo Cache
Stars: ✭ 112 (+600%)
Mutual labels:  apollo, apollo-client
matters-web
Website of Matters.News, built with Next.js.
Stars: ✭ 70 (+337.5%)
Mutual labels:  apollo, apollo-client
graphql-workshop
⚒ 🚧 A GraphQL workshop to learn GraphQL implementations
Stars: ✭ 20 (+25%)
Mutual labels:  apollo, apollo-client
laika
Log, test, intercept and modify Apollo Client's operations
Stars: ✭ 99 (+518.75%)
Mutual labels:  apollo, apollo-client
ctrip-apollo
The most delightful and handy Node.js client for ctrip apollo configuration service.
Stars: ✭ 56 (+250%)
Mutual labels:  apollo, apollo-client
nap
[Deprecated] NextJS + Apollo + PassportJS
Stars: ✭ 52 (+225%)
Mutual labels:  apollo, apollo-client
Ddp Apollo
DDP link for Apollo with GraphQL Subscriptions support
Stars: ✭ 163 (+918.75%)
Mutual labels:  apollo, apollo-client
jest-gql
✅🚀GraphQL based tests for Jest and Apollo
Stars: ✭ 33 (+106.25%)
Mutual labels:  apollo, apollo-client
RxApolloClient
RxSwift extensions for Apollo Client
Stars: ✭ 46 (+187.5%)
Mutual labels:  apollo, apollo-client
Kit
ReactQL starter kit (use the CLI)
Stars: ✭ 232 (+1350%)
Mutual labels:  apollo, apollo-client
agollo
🚀Go client for ctrip/apollo (https://github.com/apolloconfig/apollo)
Stars: ✭ 563 (+3418.75%)
Mutual labels:  apollo, apollo-client
Apollo Cache Redux
Redux cache for Apollo Client 2.0. This project is no longer maintained.
Stars: ✭ 179 (+1018.75%)
Mutual labels:  apollo, apollo-client
bookshelf
My GraphQL playground
Stars: ✭ 64 (+300%)
Mutual labels:  apollo, apollo-client
Agollo
An elegant Go client for Ctrip Apollo
Stars: ✭ 167 (+943.75%)
Mutual labels:  apollo, apollo-client
boilerplate
Boilerplate for @prisma-cms
Stars: ✭ 22 (+37.5%)
Mutual labels:  apollo, apollo-client
Reactql
Universal React+GraphQL starter kit: React 16, Apollo 2, MobX, Emotion, Webpack 4, GraphQL Code Generator, React Router 4, PostCSS, SSR
Stars: ✭ 1,833 (+11356.25%)
Mutual labels:  apollo, apollo-client
Next Graphql Blog
🖊 A Blog including a server and a client. Server is built with Node, Express & a customized GraphQL-yoga server. Client is built with React, Next js & Apollo client.
Stars: ✭ 152 (+850%)
Mutual labels:  apollo, apollo-client
apollo-cache-instorage
Apollo Cache implementation that facilitates locally storing resources
Stars: ✭ 98 (+512.5%)
Mutual labels:  apollo, apollo-client
gitstar
Github Client built with React Apollo
Stars: ✭ 15 (-6.25%)
Mutual labels:  apollo, apollo-client

react-apollo-graphql

npm CircleCI

gzip size size module formats: umd, cjs, esm

This is opinionated replacement for graphql decorator from react-apollo package.

Under development, API can change

npm install --save react-apollo-graphql

It provides:

  • simple error handling on the component level
  • readable passing of queries' results to your component
  • typed props and render props using flow type
  • server side render

Usage

Using <ApolloProvider /> from react-apollo

import GraphQL from 'react-apollo-graphql';
import ApolloClient from 'apollo-client';
import ApolloProvider from 'react-apollo';

<ApolloProvider client={new ApolloClient(...)}>
  <GraphQL render={(queries, mutations, props) => <div />} />
</ApolloProvider>

Passing ApolloClient directly

import GraphQL from 'react-apollo-graphql';
import ApolloClient from 'apollo-client';

<GraphQL client={new ApolloClient(...)} render={(queries, mutations, props) => <div />} />

Queries

In order to use define and use queries, one has to initialize them.

// @flow

import type { QueryInitializerOptions } from 'react-apollo-graphql';
import type { ApolloClient, ObservableQuery } from 'react-apollo-graphql/lib/types';

const queries = {
  // queryA will be resolved only once
  queryA: (
    client: ApolloClient,
    props: Object
  ): ObservableQuery<{ id: number }> => client.watchQuery({
    query: gql`{ id }`,
  }),
  // queryB will be resolved everytime the relevant props change
  queryB: (
    client: ApolloClient,
    props: Object,
    options: QueryInitializerOptions
  ): ObservableQuery<{ name: string }> => {
    // add our function which will be called on every props change
    options.hasVariablesChanged((currentProps, nextProps) => {
      if (currentProps.name === nextProps.name) {
        return false;
      }

      return { name: nextProps.name };
    });

    return client.watchQuery({
      query: gql`query test($name: String!) { id(name: $name)}`,
      variables: { name: props.name },
    });
  }
};

<GraphQL
  queries={queries}
  render={(initializedQueries) => {
    console.log(initializeQueries.queryA.data);
    console.log(initializeQueries.queryA.loading);
    console.log(initializeQueries.queryA.error);
    console.log(initializeQueries.queryA.networkStatus);
    console.log(initializeQueries.queryA.partial);
  }}
/>

Mutations

In 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.

// @flow

import type { ApolloClient, QueryResult } from 'react-apollo-graphql/lib/types';

const mutations = {
  registerUser: (
    client: ApolloClient,
    props: Object
  ) => (): Promise<QueryResult<{ registerUser: boolean }>> => client.mutate({
    mutation: gql`mutation registerUser($email: String!) { registerUser(email: $email) }`,
    variables: {
      email: props.email,
    },
  }),
};

<GraphQL
  email="[email protected]"
  mutations={mutations}
  render={(queries, mutations, fetchers, props) => {
    mutations.registerUser(props.email).then(
      (data) => console.log(data.registerUser),
      e => console.error(e),
    );
  }}
/>

Fetchers

In 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.

// @flow

import type { QueryInitializerOptions } from 'react-apollo-graphql';
import type { ApolloClient, QueryResult } from 'react-apollo-graphql/lib/types';

const fetchers = {
  // queryA will be resolved only once
  search: (
    client: ApolloClient,
    props: Object
  ) => (term: string): Promise<QueryResult<Array<{ id: number }>>> => client.query({
    query: gql`query search($term: String!) { search(term: $term) { id } }`,
    variables: { term },
  }),
};

<GraphQL
  fetchers={fetchers}
  text="text"
  render={(queries, mutations, fetchers, props) => {
    fetchers.search(props.text).then(
      (data) => console.log(data.search[0].id);
    );
  }}
/>

Fragments

In 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.

// @flow

import type { QueryInitializerOptions } from 'react-apollo-graphql';
import type { ApolloClient, FragmentResult } from 'react-apollo-graphql/lib/types';

const fragments = {
  // user detail will be resolved on componentWillMount and on every update if props
  // used as variables have changed
  userDetail: (
    client: ApolloClient,
    previousProps: ?Object,
    currentProps: Object
  ): FragmentResult<{ __typename: 'User', id: number, name: string }> => {
    if (previousProps && previousProps.id === currentProps.id) {
      return false;
    }

    return client.readFragment({
      id: `User:${currentProps.id}`,
      fragment: gql`fragment userDetails on User { __typename, id, name }`,
    });
  }
};

<GraphQL
  fragments={fragments}
  id={10}
  render={(queries, mutations, fetchers, fragments, props) => {
    expect(fragments.userDetail).toEqual({
      __typename: 'User',
      id: 10,
      name: 'Fero',
    });
  }}
/>

Server side render

For server side rendering you need to:

  1. import helper as import { getDataFromTree } from 'react-apollo-graphql';
  2. instantiate your view (const view = <App />;)
  3. wait for all queries to be resolved await getDataFromTree(view);
  4. render view ReactDOM.renderToString(view);
  5. profit (but you have to hydrate your apollo store on the client side 😉 )

React-Router v4

// example taken from react-router v4 docs
import { createServer } from 'http';
import ApolloClient from 'apollo-client';
import ApolloProvider from 'react-apollo';
import React from 'react';
import ReactDOMServer from 'react-dom/server';
import { StaticRouter } from 'react-router';
import { getDataFromTree } from 'react-apollo-graphql';
import App from './App';

createServer(async (req, res) => {
  const context = {};
  const client = new ApolloClient();

  const view = (
    <StaticRouter
      location={req.url}
      context={context}
    >
      <ApolloProvider client={client}>
        <App/>
      </ApolloProvider>
    </StaticRouter>
  );

  await getDataFromTree(view);

  const html = ReactDOMServer.renderToString(view);

  if (context.url) {
    res.writeHead(301, {
      Location: context.url
    });
    res.end();
  } else {
    res.write(`
      <!doctype html>
      <div id="app">${html}</div>
    `);
    res.end();
  }
}).listen(3000);

API

ApolloClient

  • apollo client is provided from apollo-client package. See documentation.

QueryInitializerOptions

// @flow

export type QueryInitializerOptions = {
  // sets function to determine if there is a relevant change in props to compute new variables
  // returns false if there is no change in props used for variables
  // or returns new variables for query.setVariables()
  hasVariablesChanged: (
    (currentProps: Object, nextProps: Object) => boolean | { [key: string]: any },
  ) => void,
};

<GraphQL fetchers?={Fetchers} fragments?={Fragments} queries?={Queries} mutations?={Mutations} render={RenderFunction} />

  • Fragments = { [key: string]: (client: ApolloClient, previousProps: ?Object, currentProps: Object) => FragmentResult<any> }
    • optional prop, object with fragments' initializer
    • each initializer will be initialized with Apollo client, previousProps and props passed to the initializer on each mount and update
    • each initializer is update only if it does not return false
    • each initializer has to return false or result of client.readFragment() (this means that it has to call the client.readFragment() method)
  • Fetchers = { [key: string]: (client: ApolloClient, props: Object) => (...args: any) => Promise<QueryResult<*>>}
    • optional prop, object with fetchers' initializer
    • each initializer will be initialized with apollo client and props passed to the initializer on each render (on mount and every update)
    • each initializer has to return (...args: any) => Promise<QueryResult<*>> (this means that it has to call the client.query() method)
  • Queries = { [key: string]: (client: ApolloClient, props: Object, options: QueryInitializerOptions) => ObservableQuery<*> }
    • optional prop, object with query initializers.
    • each initializer will be initialized with apollo client and props passed to initializer on component mount
    • each initializer has to return ObservableQuery (this means that it has to call the client.watchQuery() method)
  • Mutations = { [key: string]: (client: ApolloClient, props: Object) => () => Promise<QueryResult<*>>}
    • optional prop, object with mutation initializers
    • each initializer will be initialized with apollo client and props passed to the initializer on each render (on mount and every update)
    • each initializer has to return () => Promise<QueryResult<*>> (this means that it has to call the client.mutate() method)
  • RenderFunction = (queries: InitializedQueries, mutations: InitializedMutations, fetchers: InitializedFetchers, props: Object) => React$Element<any>
    • called on mount and updates
    • queries arg: result of each query initializer passed to the queries prop on <GraphQL /> component will be mapped to it's result, plus additional methods like fetchMore(), refetch(), etc see client.watchQuery() method
    • mutations arg: each mutation initializer from the mutations prop passed to the <GraphQL /> component will be called on render and the result will be passed under the same key to the mutations arg of render function.
    • fetchers arg: each fetcher initializer from the fetchers prop passed to the <GraphQL /> component will be called on render and the returned function will be passed under the same key to the fetchers arg of render function.
    • props arg: current props passed to <GraphQL /> component
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].