Help with React Crypto app I'm building

Hello everyone. Hoping I can get some help here. I am building a react crypto portfolio app and am having problems with adding/deleting tokens to my watchlist. There is no problem with the code until I switch page tabs(you add tokens on the search page and eventually also the coin page and can view them on picks page) and then my functions/setState ignore the data already in the array and will add duplicates. Been pulling my hair out for two days now and scoured through every forum I can. It might have to do with previous state but the only thing I can ever find on that is referring to setTimeout and updating count, which doesn’t help me at all. The issue is in src/helpers/MyPicksContext.

I have a link to a sandbox here CodeSandbox.

And here is MyPicksContext.js

import React, { createContext, useState, useEffect } from 'react';
export const MyPicksContext = createContext();

export const MyPicksContextProvider = props => {
 // console.log(localStorage.getItem('picksList'));
  const [picksList, setPicksList] = useState(
      JSON.parse(localStorage.getItem('picksList'))
    || 
      []
  )
  
  //console.log(picksList)

   useEffect(() => {
    localStorage.setItem("picksList", JSON.stringify(picksList));
  }, [picksList]);

  const deleteCoin = coin => {
    if (picksList.length === 1) {
      setPicksList([]);
    } else {
      setPicksList(picksList.filter(list => {
        console.log(list)
        //console.log(coin)
        return list !== coin;
      }))
    }
    console.log('deleted');
    console.log(picksList)
  }  

  const toggleCoin = (coin) => {
    if (picksList.length === 0) {
      setPicksList([...picksList, coin]);
    } else {
      if (picksList.indexOf(coin) === -1 ) {
        setPicksList([...picksList, coin]);
        console.log('added 1')
      } else {
        deleteCoin(coin)
      }
    }
  } 

  console.log(picksList)

  return (
    <MyPicksContext.Provider value={{ picksList, toggleCoin }}>
      {props.children}
    </MyPicksContext.Provider>
  )
}

I know I will run into more errors on this project since it is my first big react app not being built with codeacademys help. Pretty happy with how it turned out so far, but some things like this I don’t even know where to begin searching. Any help would be amazing! Please let me know if I can add anything else.

At this point I’m pretty sure it is an issue with prevState. However incorporating that into the localStorage and with conditional operators at the same time is pretty confusing.

I have done this so far. Pretty sure it’s wrong though.

const deleteCoin = coin => {
    if (picksList.length === 1) {
      setPicksList([]);
    } else {
      setPicksList((prev) => {
        return prev.filter((ele) => ele !== coin);
      })
    }
    console.log('deleted');
    console.log(picksList)
  }  

// testing prev on function 
  const toggleCoin = (coin) => {
    if (picksList.length === 0) {
      setPicksList([...picksList, coin]);
    } else { setPicksList(prevState => {
        if (!prevState.picksList.includes(coin) && !picksList.includes(coin) ) {
          setPicksList(prev => { 
            return [coin, ...prev]
          })
        } else {
        deleteCoin(coin)
        }
    })}
  }

So this solved the problem. Wasn’t previous state at all.

The issue is that .indexOf checks for referential equality of items, same as using ===. This means that const a = {id: 'x'}; const b = a; console.log(a === b); will output true, but const a = {id: 'x'}; const b = {id: 'x'}; console.log(a === b); will output false.

In your situation, upon changing pages / refreshing, the state is reset and loaded from local storage. However, this creates new objects which are not referentially equal. Instead of using .indexOf you want to use .find, something like array.find((element) => element.id === newItem.id) to find the index of the item. You could also do your own deep equality check (confirming every field matches), but I suspect the ID alone is sufficient.

In fact, I would also recommend only keeping the array of “picks” as an array of string ID’s. Then you can lookup the full data from your table for each of these ID’s. Otherwise the current price will be stored in localStorage, and could be out of date.

Thank god for stack overflow.