DEV Community

Cover image for Build a Simple ToDo App with React and GraphQL
Ayas Hussein
Ayas Hussein

Posted on

Build a Simple ToDo App with React and GraphQL

Have you ever wondered how to build a full-stack app using GraphQL instead of REST? In this tutorial, weโ€™ll walk through how to create a simple ToDo app using React and GraphQL with Apollo.

๐ŸŽฏ By the end, youโ€™ll have a working app where you can view, add, and toggle tasks โ€” powered by a GraphQL API.

Step 1: Set Up the GraphQL Server (Backend)

mkdir graphql-server
cd graphql-server
npm init -y
npm install apollo-server graphql
Enter fullscreen mode Exit fullscreen mode

Create index.js for the backend

const { ApolloServer, gql } = require('apollo-server');

const typeDefs = gql`
  type Todo {
    id: ID!
    title: String!
    completed: Boolean!
  }

  type Query {
    todos: [Todo]
  }

  type Mutation {
    addTodo(title: String!): Todo
    toggleTodo(id: ID!): Todo
  }
`;

let todos = [
  { id: "1", title: "Learn GraphQL", completed: false },
  { id: "2", title: "Build a ToDo App", completed: false },
];

const resolvers = {
  Query: {
    todos: () => todos,
  },
  Mutation: {
    addTodo: (_, { title }) => {
      const newTodo = { id: Date.now().toString(), title, completed: false };
      todos.push(newTodo);
      return newTodo;
    },
    toggleTodo: (_, { id }) => {
      const todo = todos.find(t => t.id === id);
      todo.completed = !todo.completed;
      return todo;
    },
  },
};

const server = new ApolloServer({ typeDefs, resolvers });
server.listen().then(({ url }) => {
  console.log(`๐Ÿš€ Server ready at ${url}`);
});
Enter fullscreen mode Exit fullscreen mode

Step 2: Set Up the React App (Frontend)

npx create-react-app graphql-todo
cd graphql-todo
npm install @apollo/client graphql
Enter fullscreen mode Exit fullscreen mode

in src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://localhost:4000',
  cache: new InMemoryCache(),
});

ReactDOM.render(
  <ApolloProvider client={client}>
    <App />
  </ApolloProvider>,
  document.getElementById('root')
);
Enter fullscreen mode Exit fullscreen mode

in src/App.js

import React, { useState } from 'react';
import { useQuery, useMutation, gql } from '@apollo/client';

const GET_TODOS = gql`
  query {
    todos {
      id
      title
      completed
    }
  }
`;

const ADD_TODO = gql`
  mutation($title: String!) {
    addTodo(title: $title) {
      id
      title
      completed
    }
  }
`;

const TOGGLE_TODO = gql`
  mutation($id: ID!) {
    toggleTodo(id: $id) {
      id
      completed
    }
  }
`;

function App() {
  const { data, loading } = useQuery(GET_TODOS);
  const [addTodo] = useMutation(ADD_TODO, {
    refetchQueries: [{ query: GET_TODOS }],
  });
  const [toggleTodo] = useMutation(TOGGLE_TODO);
  const [input, setInput] = useState('');

  if (loading) return <p>Loading...</p>;

  const handleAdd = () => {
    if (input.trim()) {
      addTodo({ variables: { title: input } });
      setInput('');
    }
  };

  return (
    <div style={{ padding: '2rem' }}>
      <h2>๐Ÿ“ GraphQL ToDo List</h2>
      <input value={input} onChange={e => setInput(e.target.value)} placeholder="New task" />
      <button onClick={handleAdd}>Add</button>
      <ul>
        {data.todos.map(todo => (
          <li key={todo.id} onClick={() => toggleTodo({ variables: { id: todo.id } })}>
            <span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>
              {todo.title}
            </span>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;

Enter fullscreen mode Exit fullscreen mode

Step 3 : Start the app
in backend

node index.js
Enter fullscreen mode Exit fullscreen mode

in frontend

npm start  
Enter fullscreen mode Exit fullscreen mode

๐Ÿš€ You Did It!
You now have a working React app powered by GraphQL. You can:

  1. View todos
  2. Add a new task
  3. Toggle them done/undone

What's Next?

  • Add delete functionality
  • Store data in MongoDB or PostgreSQL
  • Deploy to Vercel or Netlify

Top comments (0)