Giter Club home page Giter Club logo

gqlclientstarter's Introduction

How to set up Apollo GraphQL with TypeScript and Expo ❤️

Run the GraphQL Server

If you have ruby 3.2.2 set up on your machine feel free to clone my repo here and run rails server -b <YOUR LOCAL IP> then rails db:seed to get you started.

Set up GraphQL / Codegen the Environment

Install the dependancies

You'll need to run the following to install everything in the project you need for graphql

yarn add @apollo/client graphql
yarn add -D @graphql-codegen/cli @graphql-codegen/client-preset @parcel/watcher

Set up your codegen.ts

Create this codegen.ts file and populate it with the following

import { CodegenConfig } from "@graphql-codegen/cli";

const config: CodegenConfig = {
  schema: "http://<YOUR_LOCAL_IP>:3000/graphql",
  documents: ["src/**/*.{ts,tsx,graphql}"],
  generates: {
    "./src/__generated__/": {
      preset: "client",
      plugins: [],
      presetConfig: {
        gqlTagName: "gql",
        fragmentMasking: false,
      },
    },
  },
  ignoreNoDocuments: true,
};

export default config;

After this you can add the following scripts to your package.json

{
    ...
    "compile": "graphql-codegen",
    "watch": "graphql-codegen -w"
}

Go back into your App.tsx and wrap the Home component with the Apollo Provider

import { ApolloClient, ApolloProvider, InMemoryCache } from "@apollo/client";
import { Home } from "./src/Home";

const client = new ApolloClient({
  uri: "http://192.168.2.28:3000/graphql",
  cache: new InMemoryCache(),
});

export default function App() {
  return (
    <ApolloProvider client={client}>
      <Home />
    </ApolloProvider>
  );
}

At this point you should be able to add a graphql query to any file in your app and run yarn run compile or watch to be able to import the typed GraphQL files. Make sure to import gql from the __generated__ in order to have actual type safety

Back in the src directory let make a query file graphql/author.ts

Writing your queries

A note on code structure

When you use your GraphQL queries its usually a good idea to wrap them with a hook. You could, of course, just invoke useMutation and useQuery and hope for the best; but with all things in software, its usually best to keep things organized.

Get All Todos Hook

Here we start by creating a folder to hold our hooks called hooks. Inside this folder, create a new file called useTodosByAuthorId.ts. You'll want to create this file:

import { useQuery } from "@apollo/client";
import { gql } from "../__generated__";

export const GET_TODOS_FOR_AUTHOR = gql(`
  query GetTodosForAuthor($id:ID!) {
    getTodosForAuthor(id:$id) {
      id
      authorId
      title
      message
      completed
    }
  }
`);

export const useTodosByAuthorId = (id: string) => {
  const result = useQuery(GET_TODOS_FOR_AUTHOR, {
    variables: {
      id,
    },
  });

  return result;
};

We then go back to home and hard code the author id to 1

export function Home() {
  const [visible, setVisible] = useState(false);

  const { data, loading, error, refetch } = useTodosByAuthorId("1");

We can then just plug this into the FlatList

<FlatList
  data={data?.getTodosForAuthor}
  renderItem={(data) => {
    return <ListItem item={data.item} onPress={() => {}} />;
  }}
/>

Restarting the app should grab all the todos for that author

Create Todos Hook

We are going to start by creating a fragment so we can share code. This can be done in three steps

  1. Create a src/hooks/Fragments.ts file that will house our fragments
  2. Add a fragment for the Essential items of a Todo to the file
import { gql } from "../__generated__";

export const ESSENTIALS_FRAGMENT = gql(`
  fragment Essentials on Todo {
    authorId
    id
    title
    message
    completed
  }
`);
  1. Register the Fragment.
import { createFragmentRegistry } from "@apollo/client/cache";

const client = new ApolloClient({
  uri: "http://192.168.2.28:3000/graphql",
  cache: new InMemoryCache({
    fragments: createFragmentRegistry(ESSENTIALS_FRAGMENT),
  }),
});

Next lets refactor the useTodosByAuthorId hook to use the fragment:

export const GET_TODOS_FOR_AUTHOR = gql(`
  query GetTodosForAuthor($id:ID!) {
    getTodosForAuthor(id:$id) {
      ...Essentials
    }
  }
`);

Finally lets make the Create Todo Hook src/hooks/useCreateTodo.ts:

import { useMutation } from "@apollo/client";

import { gql } from "../__generated__";

export const CREATE_TODO_FOR_AUTHOR = gql(`
  mutation CreateTodoForAuthor($title:String!, $message:String!, $authorId:ID!) {
    createTodo(input: { title:$title, message:$message, authorId:$authorId }) {
      ...Essentials
    }
  }
`);

export const useCreateTodo = (authorId: string) => {
  const [createTodo, { loading, error, data }] = useMutation(
    CREATE_TODO_FOR_AUTHOR
  );

  const createNewTodo = async (title: string, message: string) => {
    await createTodo({
      variables: {
        title,
        message,
        authorId,
      },
    });
  };

  return {
    createNewTodo,
    loading,
    error,
    data,
  };
};

We can then update Home to have the same properties

  const { data, loading, error, refetch } = useTodosByAuthorId("1");
  const { createNewTodo } = useCreateTodo("1");

  ...

  const createTodo = async (title: string, message: string) => {
    await createNewTodo(title, message);
    setVisible(false);
    refetch();
  };

Mark Todo as Complete Hook

Create a new file useCompleteTodo.ts

Enter the following Code:

import { gql, useMutation } from "@apollo/client";

import { useCallback } from "react";

export const COMPLETE_TODO = gql(`
  mutation CompleteTodo($authorId:ID!, $todoId:ID!, $completed:Boolean!) {
    completeTodo(input:{
      authorId:$authorId,
      todoId:$todoId,
      completed:$completed
    }) {
      ...Essentials
    }
  }
`);

export const useCompleteTodo = (authorId: string) => {
  const [completeTodo, { error, loading, data }] = useMutation(COMPLETE_TODO);

  const markTodoAsComplete = useCallback((todoId: string, completed = true) => {
    completeTodo({
      variables: {
        authorId,
        todoId,
        completed,
      },
    });
  }, []);

  return {
    markTodoAsComplete,
    error,
    loading,
    data,
  };
};

Finally update the home component one last time

const { markTodoAsComplete } = useCompleteTodo("1");

<FlatList
  data={data.getTodosForAuthor}
  renderItem={(data) => {
    const onPress = () => {
      markTodoAsComplete(data.item.id, !data.item.completed);
    };
    return <ListItem item={data.item} onPress={onPress} />;
  }}
/>;

Now everything should work

gqlclientstarter's People

Contributors

friyiajr avatar

Stargazers

Rajesh Rajappan avatar

Watchers

 avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.