Home > front end >  Show fav items from localStorage after refresh browser - Next.js & Typescript project
Show fav items from localStorage after refresh browser - Next.js & Typescript project

Time:12-19

I am doing a personal project in Next.js and Typescript where I get some data from an API. Then, I do a list of some items. I want to make a favourite list out of them and store them in localStorage. The code works fine, but if I refresh the browser, the items get un favourite. However, they are in the localStorage. I would like to have the items favourited after the refresh. As a second question, if also can I make the fav items on top of the others would be fantastic. I am sure is in this line where I have to fix the code, but I do not know how:

{favourites.includes(value.properties.title) || (localStorage.getItem('favourite') !== null) ?

This is the whole code:

import { GetStaticProps, InferGetStaticPropsType } from "next";

import { FaHeart } from "react-icons/fa";
import { FaRegHeart } from "react-icons/fa";
import styles from '../styles/Home.module.css'
import { useState } from "react";

type Data = {
  message: string;
  result: [
    {
      properties: {
        characters: string[];
        planets: string[];
        starships: string[];
        vehicles: string[];
        species: string[];
        created: string;
        edited: string;
        producer: string;
        title: string;
        episode_id: number;
        director: string;
        release_date: string;
        opening_crawl: string;
        url: string;
      };
    }
  ];
};

export const getStaticProps: GetStaticProps<{ swapis: Data }> = async () => {
  const res = await fetch("https://www.swapi.tech/api/films/");
  const swapis: Data = await res.json();

  return {
    props: {
      swapis
    }
  };
};

const Home = ({
  swapis
}: InferGetStaticPropsType<typeof getStaticProps>) => {
  console.log('swapis', swapis);

  const [searchFilm, setSearchFilm] = useState<string>('');
  const [favourites, setFavourites] = useState<Array<string>>([]);

  const addFav = (props: any) => {
    let array = favourites;
    let addArray = true;
    array.map((item: any, key: number) => {
      if (item === props.value.properties.title) {
        array.splice(key, 1);
        addArray = false;
      }
    });
    if (addArray) {
      array.push(props.value.properties.title)
    }
    setFavourites([...array])
    localStorage.setItem('favourites', JSON.stringify(favourites));

    var storage = localStorage.getItem('favItem'   (props.value.properties.title) || '0')
    if (storage == null) {
      localStorage.setItem(('favItem'   (props.value.properties.title)), JSON.stringify(props))
    } else {
      localStorage.removeItem('favItem'   (props.value.properties.title))
    }
  }
  

  return (
    <>
      <h1>List of Films</h1>
      <div className={styles.containerTable}>
        <input type="text" value={searchFilm} placeholder="Search films.." onChange={e => setSearchFilm(e.target.value)} />
      </div>
      {Object.entries(swapis?.result || {})
      .filter(([key, value]) => {
        if (!searchFilm) return true;
        if (value.properties.title.toLowerCase().includes (searchFilm)) return true;
        return false;
      })
      .map(([key, value]) => (
        <table key={key} className={styles.containerTable}>
          <tr className={styles.films}>
            <td className={styles.films}>{value.properties.title} {favourites.includes(value.properties.title) || (localStorage.getItem('favourite') !== null) ? (
              <FaHeart onClick={() => addFav({ value })} />
            ) : (
              <FaRegHeart onClick={() => addFav({ value})} />
            )}</td>
          </tr>
        </table>
      ))}
    </>
  );
};

export default Home;

CodePudding user response:

I would separate answer into 2 parts according to your questions.

  1. Question - Store favorite films into localStorage and keep them stored after refreshing pages.

Just a few notes

  • if your intention with addFav method is just to toggle favourite films in localStorage then I think its too complicated business logic you wrote. I would just separate it into addFav and removeFav methods and that is it.
const addFav = (id) => {
    setFavourites([...favourites, id]);
};

const removeFav = (id) => {
    setFavourites([...favourites.filter((found) => found !== id)]);
};

// Store in localstorage if favourites variable changes
useEffect(() => {
    localStorage.setItem("favourites", JSON.stringify(favourites));
}, [favourites]);

  • The reason you don't see favourite items after refreshing page is because favourites variable is always set to [] when Home component is first rendered.
const [favourites, setFavourites] = useState(
    JSON.parse(localStorage.getItem("favourites")) || []
);
  • I would not use film title as an identification, cause you can't be sure that the key is unique from API response.
  1. Question - Listing favourite ones first
  • I would personally separate array of filtered films into 2 arrays

Here is https://codesandbox.io/s/strange-buck-voy0z?file=/src/App.js where are favourite movies immediately sorted as first after changing their states.

  • Related