How add data from API to favourite and save in localStorage

I would like to save the books fetched from the API to favourites and keep a list of favourite books in localStorage so that when the page is refreshed, the favourites list does not disappear.

The books are fetched from the API in the BooksView.js component. The API is constructed in such a way that only 10 books can be fetch and to fetch and display more books I have to send a request for another 10 from the next page in the API. I use the ChangePageButton to send a new request and download more books

In the BookView.js component the list of books fetched from API is saved to a new array of objects and for each book a new key is added with information if the book is in favorites or not. I map the newly created array and if the book has the favourite: true key I display a full heart icon ( <FavouriteBook>) and if it doesn’t have the favourite key I display an empty heart icon.

My problem is that I fetch a list of 10 books from the API and when I fetch a list of more books it overwrites the favorites list with the new list of books.

I don’t know how to solve this problem to save list of favorite books in separate variable which will be saved in localStorage and when opening page list of favorite books will be downloaded from localStorage and selected books will be marked as favorite.

BookView.js

import { styled as materialUIStyled } from "@mui/material/styles";
import Paper from "@mui/material/Paper";
import Button from "@mui/material/Button";
import Link from "@mui/material/Link";
import styled from "styled-components";

import { Grow } from "@mui/material";
import BookCover from "../images/default_book_cover.jpg";
import FavouriteBook from "../favourite-book";
import { useEffect, useState } from "react";

const Img = materialUIStyled("img")({
  margin: "0px",
  display: "block",
  maxWidth: "150px",
  maxHeight: "200px",
});
const MainStyles = styled.div`
  display: flex;
`;
const BooksContainer = styled(MainStyles)`
  //   height: 100vh;
  gap: 20px;
  flex-wrap: wrap;
  justify-content: center;
  margin: 0 50px;
`;

const BookContainer = styled(MainStyles)`
  gap: 5px;
  padding: 15px;
  flex-wrap: wrap;
  justify-content: center;
`;
const BookInfoContainer = styled(MainStyles)`
  gap: 30px;
  width: 100%;
  margin: 10px;
`;

const BookInfoParagraph = styled.span`
  font-size: 16px;
`;
const BookTitleName = styled.h2`
  margin: 2px;
  font-size: 20px;
  font-weight: bold;
`;
const ErrorContainer = styled(BooksContainer)`
  font-size: 50px;
  align-items: center;
  height: 100vh;
  text-align: center;
`;
const ButtonsContainer = styled(MainStyles)`
  gap: 20px;
`;

const BookView = ({ data, setData, error, errorMessage }) => {
  const [favorites, setFavorites] = useState([]);

  useEffect(() => {
    setFavorites(data);
  }, [data]);

  useEffect(() => {
    console.log(favorites);
    console.log(data);
  }, [favorites]);

  if (error) {
    return (
      <ErrorContainer>
        <p>
          Error
          <br></br>
          {errorMessage}
        </p>
      </ErrorContainer>
    );
  }

  function handleFavorite(id) {
    const newFavorites = favorites.map(item => {
      return item.id === id ? { ...item, favorite: !item.favorite } : item;
    });

    setFavorites(newFavorites);
  }
  return (
    <BooksContainer>
      {Array.isArray(data) &&
        data.map(
          book =>
            book.type === "Text" && (
              <Grow key={book.id} in timeout={500}>
                <Paper
                  sx={{
                    p: 2,
                    width: "450px",
                  }}>
                  <BookContainer>
                    <BookInfoContainer>
                      {book.resources.map(
                        item =>
                          item.type === "image/jpeg" &&
                          item.uri.includes("medium") && (
                            <Link
                              target="blank"
                              href={`https://www.gutenberg.org/ebooks/${book.id}`}>
                              <Img
                                key={item.id}
                                alt="book-cover"
                                src={item.uri}
                              />
                            </Link>
                          )
                      )}
                      {book.resources.length < 11 && (
                        <Img alt="book-cover" src={BookCover} />
                      )}
                      <div>
                        <BookInfoParagraph>Book title:</BookInfoParagraph>
                        <BookTitleName>{book.title}</BookTitleName>
                        <BookInfoParagraph>Author:</BookInfoParagraph>

                        {book.agents.map(
                          item =>
                            item.type === "Author" && (
                              <BookTitleName key={item.id}>
                                {item.person}
                              </BookTitleName>
                            )
                        )}
                      </div>
                    </BookInfoContainer>
                    <ButtonsContainer>
                      {book.resources.map(
                        item =>
                          item.type.includes("text/html") &&
                          item.uri.includes(".htm") && (
                            <Button key={item.id} variant="outlined">
                              <Link
                                underline="none"
                                target="blank"
                                href={item.uri}>
                                QUICK READ BOOK
                              </Link>
                            </Button>
                          )
                      )}
                      {favorites.map(
                        (item, i) =>
                          book.id === item.id && (
                            <FavouriteBook
                              key={item.id}
                              add={item.favorite}
                              handleClick={() => {
                                handleFavorite(item.id);
                              }}
                            />
                          )
                      )}
                    </ButtonsContainer>
                  </BookContainer>
                </Paper>
              </Grow>
            )
        )}
    </BooksContainer>
  );
};

export default BookView;

BooksView.js

import { useEffect, useState } from "react";
import axios from "axios";
import PageWrapper from "../../common/page-wrapper";
import ChangePageButton from "./change-page-button";
import BookView from "./book-view";
import ProgressCircle from "./progress-circle";
import styled from "styled-components";

const ChangePageButtonContainer = styled.div`
  position: fixed;
  top: 50%;
  left: ${props => props.theme.left};
  right: ${props => props.theme.right};
`;
const leftPosition = {
  left: "15px",
};
const rightPosition = {
  right: "15px",
};
const BooksView = () => {
  const [data, setData] = useState(null);
  const [isLoading, setIsLoading] = useState(true);
  const [forwardPageLoading, setForwardPageLoading] = useState(false);
  const [backPageLoading, setBackPageLoading] = useState(false);
  const [page, setPage] = useState(1);
  const [error, setError] = useState(false);
  const [errorMessage, setErrorMessage] = useState("");
  useEffect(() => {
    fetchData(page);
  }, [page]);

  const fetchData = page => {
    axios(`https://gnikdroy.pythonanywhere.com/api/book/?page=${page}`)
      .then(res => {
        setData(res.data.results);
        setIsLoading(false);
        setForwardPageLoading(false);
        setBackPageLoading(false);
      })
      .catch(err => {
        setError(true);
        setIsLoading(false);
        setErrorMessage(err.message);
        console.log("Error", err.message);
      });
  };

  let count = page;
  const handleForwardPage = () => {
    setForwardPageLoading(true);
    if (page === 6578) {
      setPage(1);
    } else {
      count += 1;
      setPage(count);
    }
  };
  const handleBackPage = () => {
    setBackPageLoading(true);
    if (count === 1) {
      setPage(6578);
    } else {
      count -= 1;
      setPage(count);
    }
  };
  // console.log("data", data);

  return (
    <>
      {isLoading ? (
        <ProgressCircle height="100vh" />
      ) : (
        <PageWrapper>
          <ChangePageButtonContainer
            theme={leftPosition}
            style={{ display: `${error ? "none" : "inherit"}` }}>
            {backPageLoading ? (
              <ProgressCircle />
            ) : (
              <ChangePageButton handleClick={handleBackPage} type="back" />
            )}
          </ChangePageButtonContainer>

          <section>
            <BookView
              setData={setData}
              data={data}
              error={error}
              errorMessage={errorMessage}
            />
          </section>
          <ChangePageButtonContainer
            style={{ display: `${error ? "none" : "inherit"}` }}
            theme={rightPosition}>
            {forwardPageLoading ? (
              <ProgressCircle />
            ) : (
              <ChangePageButton
                handleClick={handleForwardPage}
                type="forward"
              />
            )}
          </ChangePageButtonContainer>
        </PageWrapper>
      )}
    </>
  );
};

export default BooksView;

FavouriteBook.js

import { Button, Icon } from "@mui/material";

const FavouriteBook = ({ handleClick, add }) => {
  return (
    <Button onClick={handleClick}>
      <Icon sx={{ color: "red" }}>{add ? "favorite" : "favorite_border"}</Icon>
    </Button>
  );
};

export default FavouriteBook;