IndexDB using Dexie in React - Veltris

IndexDB using Dexie in React

February 8, 2022 | Akshay Malta

    What is IndexDB?

    When you want to make your application really fast without calling API’s to the backend every time, We want to store the data on the browser itself and can play with the data from the browser only. It can be used with offline apps and can be combined with ServiceWorkers . According to the definition of IndexedDB on MDN:

    “IndexedDB is a low-level API for client-side storage of significant amounts of structured data, including files/blobs. This API uses indexes to enable high-performance searches of this data. While DOM Storage is useful for storing smaller amounts of data, it is less useful for storing larger amounts of structured data. IndexedDB provides a solution.”

    Sometimes a question arises, can we use localStorage instead of IndexedDB?

    IndexedDB is much more powerful than localStorage. It has the following advantages:

    1. Stores almost any kind of value by keys, multiple key types.
    2. Supports key range queries, indexes.
    3. Can store much bigger volumes of data than localStorage.

    How to use IndexDB in React?

    So, I have used a DEXIE library to handle it. According to the dexie :

    ‘Dexie.js is a wrapper library for indexedDB — the standard database in the browser.

    Dexie solves three main issues with the native IndexedDB API:

    1. Ambiguous error handling
    2. Poor queries
    3. Code complexity

    Dexie provides a neat database API with a well-thought-through API design, robust error handling, extendability, change tracking awareness and extended KeyRange support (case insensitive search, set matches and OR operations).’

    Now, we can start the example without further ado:

    We will create book store where we display thousands of data on the table with the pagination implemented. We will store the books data on indexDB on the first render of the page and will play with that data later.

    Install Dexie using npm i dexie.

    • In App.js we did the following thing:

    Created two components:

    AppBar: to display the header

    BookTable: to display the books data in table format.

    • Created the instance of the dexie and defined the store and its version. In store we added the id which is auto-incremented and also contains the JSON keys.
    • In setAllData we got whole data from the API and stored in the IndexDb bys using bulkAdd() method.
    • In getTotalCount we get the total count of the data in the db by using count() method
    • In getData we get the paginated data from the IndexDB by using offset() (start reading data), limit() (total number of data), toArray()(format of data)
    import React from "react";
    import { makeStyles } from "@material-ui/core/styles";
    import Paper from "@material-ui/core/Paper";
    import Table from "@material-ui/core/Table";
    import TableBody from "@material-ui/core/TableBody";
    import TableCell from "@material-ui/core/TableCell";
    import TableContainer from "@material-ui/core/TableContainer";
    import TableHead from "@material-ui/core/TableHead";
    import TablePagination from "@material-ui/core/TablePagination";
    import TableRow from "@material-ui/core/TableRow";
    const columns = [
      { id: "authors", label: "AUTHORS", minWidth: 130 },
      { id: "title", label: "TITLE", minWidth: 130 },
      {
        id: "price",
        label: "PRICE",
        minWidth: 130,
      }
    ];
    const useStyles = makeStyles({
      root: {
        width: "100%",
      },
      container: {
        maxHeight: 700,
      },
    });
    const BookTable = (props) => {
      const classes = useStyles();
      const handleChangePage = (event, newPage) => {
        props.pageChanged(newPage + 1);
      };
      return (
        <Paper className={classes.root}>
          <TableContainer className={classes.container}>
            <Table stickyHeader aria-label="sticky table">
              <TableHead>
                <TableRow>
                  {columns.map((column) => (
                    <TableCell
                      key={column.id}
                      style={{ minWidth: column.minWidth }}
                    >
                      {column.label}
                    </TableCell>
                  ))}
                </TableRow>
              </TableHead>
              <TableBody>
                {props.totalData.map((row) => {
                  return (
                    <TableRow tabIndex={-1} key={row.id}>
                      {columns.map((column) => {
                        const value = row[column.id];
                        return (
                          <TableCell key={column.id} align={column.align}>
                           {value}
                          </TableCell>
                        );
                      })}
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          </TableContainer>
          <TablePagination
            rowsPerPage={15}
            component="div"
            count={props.totalCount}
            page={props.offSet - 1}
            onChangePage={handleChangePage}
            rowsPerPageOptions={[]}
          />
        </Paper>
      );
    };
    export default BookTable;

    App.js code

    import React from "react";
    import { makeStyles } from "@material-ui/core/styles";
    import Paper from "@material-ui/core/Paper";
    import Table from "@material-ui/core/Table";
    import TableBody from "@material-ui/core/TableBody";
    import TableCell from "@material-ui/core/TableCell";
    import TableContainer from "@material-ui/core/TableContainer";
    import TableHead from "@material-ui/core/TableHead";
    import TablePagination from "@material-ui/core/TablePagination";
    import TableRow from "@material-ui/core/TableRow";
    const columns = [
      { id: "authors", label: "AUTHORS", minWidth: 130 },
      { id: "title", label: "TITLE", minWidth: 130 },
      {
        id: "price",
        label: "PRICE",
        minWidth: 130,
      }
    ];
    const useStyles = makeStyles({
      root: {
        width: "100%",
      },
      container: {
        maxHeight: 700,
      },
    });
    const BookTable = (props) => {
      const classes = useStyles();
      const handleChangePage = (event, newPage) => {
        props.pageChanged(newPage + 1);
      };
      return (
        <Paper className={classes.root}>
          <TableContainer className={classes.container}>
            <Table stickyHeader aria-label="sticky table">
              <TableHead>
                <TableRow>
                  {columns.map((column) => (
                    <TableCell
                      key={column.id}
                      style={{ minWidth: column.minWidth }}
                    >
                      {column.label}
                    </TableCell>
                  ))}
                </TableRow>
              </TableHead>
              <TableBody>
                {props.totalData.map((row) => {
                  return (
                    <TableRow tabIndex={-1} key={row.id}>
                      {columns.map((column) => {
                        const value = row[column.id];
                        return (
                          <TableCell key={column.id} align={column.align}>
                           {value}
                          </TableCell>
                        );
                      })}
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          </TableContainer>
          <TablePagination
            rowsPerPage={15}
            component="div"
            count={props.totalCount}
            page={props.offSet - 1}
            onChangePage={handleChangePage}
            rowsPerPageOptions={[]}
          />
        </Paper>
      );
    };
    export default BookTable;

    appBar.js

    import React from "react";
    import { makeStyles } from "@material-ui/core/styles";
    import Paper from "@material-ui/core/Paper";
    import Table from "@material-ui/core/Table";
    import TableBody from "@material-ui/core/TableBody";
    import TableCell from "@material-ui/core/TableCell";
    import TableContainer from "@material-ui/core/TableContainer";
    import TableHead from "@material-ui/core/TableHead";
    import TablePagination from "@material-ui/core/TablePagination";
    import TableRow from "@material-ui/core/TableRow";
    const columns = [
      { id: "authors", label: "AUTHORS", minWidth: 130 },
      { id: "title", label: "TITLE", minWidth: 130 },
      {
        id: "price",
        label: "PRICE",
        minWidth: 130,
      }
    ];
    const useStyles = makeStyles({
      root: {
        width: "100%",
      },
      container: {
        maxHeight: 700,
      },
    });
    const BookTable = (props) => {
      const classes = useStyles();
      const handleChangePage = (event, newPage) => {
        props.pageChanged(newPage + 1);
      };
      return (
        <Paper className={classes.root}>
          <TableContainer className={classes.container}>
            <Table stickyHeader aria-label="sticky table">
              <TableHead>
                <TableRow>
                  {columns.map((column) => (
                    <TableCell
                      key={column.id}
                      style={{ minWidth: column.minWidth }}
                    >
                      {column.label}
                    </TableCell>
                  ))}
                </TableRow>
              </TableHead>
              <TableBody>
                {props.totalData.map((row) => {
                  return (
                    <TableRow tabIndex={-1} key={row.id}>
                      {columns.map((column) => {
                        const value = row[column.id];
                        return (
                          <TableCell key={column.id} align={column.align}>
                           {value}
                          </TableCell>
                        );
                      })}
                    </TableRow>
                  );
                })}
              </TableBody>
            </Table>
          </TableContainer>
          <TablePagination
            rowsPerPage={15}
            component="div"
            count={props.totalCount}
            page={props.offSet - 1}
            onChangePage={handleChangePage}
            rowsPerPageOptions={[]}
          />
        </Paper>
      );
    };
    export default BookTable;

    table.js

    Data stored in indexDB

    output

    Well, that’s all, I hope I have provided a basic understanding of indexDB. Here is the Github repository: https://github.com/akshay1malta/indexdb

    ❤️ Like, Share or Leave A Comment!

    If you enjoyed this post, don’t forget to give it a 👏🏼, share it with a friend you think might benefit from it, and leave a comment! Stay tuned for more exciting blogs on Flutter, Elixir, React, Angular, Ruby, etc.

    Thanks !!

    Related Articles