0

In a weather app, I have tried to create an add to favorites function. So far, it works partially, but with some bugs that I can't seem to solve because I don't really understand what is even causing them.

Component:

import React, { ReactNode, useState } from 'react';
interface Props {
  location?: string;
}
export const AddFavorite: React.FC<Props> = ({ location }: Props) => {
  let favorites: any = [];
  // const [favorite, setFavorite] = useState(false);
  const toggleFavoriteBtn = () => {
    const storageFavorites = localStorage.getItem('favorites');
    const index: number = favorites.indexOf(location);

    favorites = storageFavorites ? JSON.parse(storageFavorites) : [];
    if (index > -1) {
      favorites.splice(index, 1);
      // setFavorite(false);
    } else {
      favorites.push(location);
      // setFavorite(true);
    }
    localStorage.setItem('favorites', JSON.stringify(favorites));
  };
  return (
    <div>
      <button type="button" onClick={toggleFavoriteBtn}>
        {/* {favorite ? 'favorited' : 'not favorited'} */}
        favorite
      </button>
    </div>
  );
};

For now, I have commented out the useState part, but I will get to that later.

Pretty much, if I run this code and test the button, I can add and remove a location without any issues UNLESS I reload the page or for instance add another location, and then go back to a location which I have previously added. Then suddenly, my array no longer understands that the location is already in the array, and adds it again, and it just goes bananas thereafter and nothing makes logical sense.

Is it the way the code is set up to begin with or is there something I have missed doing?

Secondly, I added the useState part which is commented out right now, because the whole reason I wanted to use it is to be able to change the appearance of the button when the location is favorited or not. However, it completely ruins my function (I can't see why it could even affect that though) and instead of removing and adding an item in a normal matter, for each click it just goes in this illogical loop of:

  1. adding the location
  2. adding the location again (so it's now twice in the array)
  3. removing one of the duplicate locations

(each step is a click) So the next time you click 3 times, there's 2 of the same location remaining, and the next time there's 3 and so and so forth..

Is this perhaps because useState does some strange page reload so it's actually just the previous bug that is running or what is going on..? ._.

jrwebbie
  • 99
  • 1
  • 11

1 Answers1

1

The biggest issue you were having is that you weren't loading the favorites array from localStorage when building the component.

Although, if you have multiple of the AddFavorite components being rendered, the way I modified this will fail because the favorites array won't be updated when a different component makes a change.

In order to get the components to be updated on other components making changes, I'd suggest using redux, context, or just maintaining the favorites array in a parent component.

import React, { ReactNode, useState, useEffect } from 'react';
interface Props {
  location?: string;
}
export const AddFavorite: React.FC<Props> = ({ location }: Props) => {
  let [favorites, setFavorites] = useState(():any[]=>JSON.parse(localStorage.getItem('favorites')||'[]'));
  const favorite = favorites.includes(location);
  // const [favorite, setFavorite] = useState(false);
  useEffect(() => {
    const funct =  ()=>{
      setFavorites(JSON.parse(localStorage.getItem('favorites')||'[]'));
    };
    window.addEventListener('storage',funct);
    return () => {
      window.removeEventListener('storage',funct);
    }
  }, [])
  const toggleFavoriteBtn = () => {
    const index: number = favorites.indexOf(location);
    const newFavorites = favorites.slice();
    if (index > -1) {
      newFavorites.splice(index, 1);
      // setFavorite(false);
    } else {
      newFavorites.push(location);
      // setFavorite(true);
    }
    setFavorites(newFavorites);
    localStorage.setItem('favorites', JSON.stringify(newFavorites));
  };
  return (
    <div>
      <button type="button" onClick={toggleFavoriteBtn}>
        {favorite ? 'favorited' : 'not favorited'}
        favorite
      </button>
    </div>
  );
};
Zachary Haber
  • 10,376
  • 1
  • 17
  • 31
  • Thank you so so much for your help and the recommendation! I ended up using context , and it works like magic :) – jrwebbie Apr 12 '20 at 13:04