DEV Community

Cover image for Build a CRUD App in React with Tanstack Query and Material UI [Part 1]
Ihor Filippov
Ihor Filippov

Posted on • Edited on

Build a CRUD App in React with Tanstack Query and Material UI [Part 1]

If simply reading this tutorial isn't enough for you, you can go here and write code alongside it.


In order to follow along with this tutorial, you'll need a basic knowledge of HTML, CSS, and JavaScript/ES6. You should also know the fundamentals of React, which you can learn by reading Quick Start with React.

In this tutorial we will make a simple CRUD app. We will fetch users from the remote API and you will be able to add, update or delete them.

While implementing this app we will use:

Here is a diagram of what we will implement.

Image description

As you can see, here are two sections each with its own responsibility. One for create and edit user data and another for visualize the list of users.

First, let's a component responsible for all users data on the page.

components/users.js



import { Container } from '@mui/material';

export const Users = () => {
  return (
    <Container 
      maxWidth="md" 
      sx={{ margin: '20px auto' }}>
    </Container>
  );
}


Enter fullscreen mode Exit fullscreen mode

The Container component is used to center your content horizontally.

  • maxWidth="md": This sets the maximum width of the container. The md value means that the maximum width is set to the value defined for medium-sized screens in Material-UI's theme. This is a way to make the component responsive.
  • sx={{ margin: '20px auto' }}: This is a shorthand for inline styles. sx is a special property provided by Material-UI for customizing styles.

Then, let's implement a component to render list of users.

components/users-table.js



import { 
  Paper, 
  Table, 
  TableBody, 
  TableCell, 
  TableContainer, 
  TableHead, 
  TableRow 
} from "@mui/material"

export const UsersTable = () => {
  return (
    <TableContainer component={Paper}>
      <Table>
        <TableHead>
          <TableRow>
            <TableCell>Name</TableCell>
            <TableCell>Email</TableCell>
          </TableRow>
        </TableHead>
        <TableBody></TableBody>
      </Table>
    </TableContainer>
  );
}


Enter fullscreen mode Exit fullscreen mode

Let's explain the code above.

  • <TableContainer component={Paper}>: The TableContainer component is used as a container for the Table. It uses the Paper component as its base, which gives it a Material design look with a shadow and background.
  • Table, TableHead, TableBody, TableRow and TableCell are just wrappers for native elements of the table.

Now, import UsersTable inside Users.

components/users.js



import { Container } from '@mui/material';
import { UsersTable } from './users-table';

export const Users = () => {
  return (
    <Container 
      maxWidth="md" 
      sx={{ margin: '20px auto' }}>
      <UsersTable />
    </Container>
  );
}


Enter fullscreen mode Exit fullscreen mode

And Users inside App.

App.js



import { Users } from './components/users';

export default function App() {
  return <Users />;
}


Enter fullscreen mode Exit fullscreen mode

At this moment you should see three table head sections without any data inside the table. It is an expected behaviour.

Now, let's fetch and render data about our users.

To do this, first of all we need to initialize a QueryClient and provide it to the application through a QueryClientProvider.

index.js



import React from "react";
import { createRoot } from "react-dom/client";
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';

import App from "./App";

const queryClient = new QueryClient();

const root = createRoot(document.getElementById("root"));

root.render(
  <QueryClientProvider client={queryClient}>
    <App />
  </QueryClientProvider>
);


Enter fullscreen mode Exit fullscreen mode

Then, we need to define a layer responsible for data fetching.

api/use-users.js



import { useQuery } from "@tanstack/react-query"
import axios from "axios";

export const useUsers = () => {
  return useQuery({
    queryKey: ['users'],
    queryFn: async () => {
     const { data } = await axios.get(
      'https://jsonplaceholder.typicode.com/users'
     );
     return data;
    }
  });
}


Enter fullscreen mode Exit fullscreen mode

Here we utilize useQuery hook from React Query library inside our own custom hook useUsers.

  • queryKey: ['users'] is a unique identifier, which is used by React Query to cache and retrieve the query's data.
  • queryFn is an asynchronous function that defines how to fetch the data. This function will be called by React Query to load the data.

Now, let's use useUsers inside our App component.

App.js



import { Users } from './components/users';
import { useUsers } from './api/use-users';

export default function App() {
  const { isFetching, isError, data } = useUsers();

  if (isFetching) {
    return <div>Loading...</div>;
  }

  if (isError) {
    return <div>Error</div>;
  }

  return <Users users={data} />;
}


Enter fullscreen mode Exit fullscreen mode

Then, let's handle users inside Users component and pass it down to UsersTable.

components/users.js



...imports
export const Users = ({ users }) => {
  return (
    <Container 
      maxWidth="md" 
      sx={{ margin: '20px auto' }}>
      <UsersTable users={users} />
    </Container>
  );
}


Enter fullscreen mode Exit fullscreen mode

Finally, we can render our users.

components/users-table.js



...imports
export const UsersTable = ({ users }) => {

  const renderUsers = (users) => {
    return users.map(user => {
      return (
        <TableRow key={user.id}>
          <TableCell>{user.name}</TableCell>
          <TableCell>{user.email}</TableCell>
        </TableRow>
      );
    })
  }

  return (
    <TableContainer component={Paper}>
      <Table>
        <TableHead>
          <TableRow>
            <TableCell>Name</TableCell>
            <TableCell>Email</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>{renderUsers(users)}</TableBody>
      </Table>
    </TableContainer>
  );
}


Enter fullscreen mode Exit fullscreen mode

To be continued...

Top comments (2)

Collapse
 
9opsec profile image
9opsec

That link to the code-along site is pretty neat. That's a great way to learn.

Collapse
 
igorfilippov3 profile image
Ihor Filippov

Thank you ❤️