How to immutably update an array and store it in local storage in React?
P粉604669414
P粉604669414 2024-04-02 09:51:18
0
1
307

I'm making a recipe app. I want the user to be able to add recipes to a favorites list. There are 3 React components involved. Recipes, add to favorites and favorites.

The Recipe component displays various details about the selected recipe.

The AddToFavorites component is a button rendered in the Recipe component.

The Favorites component is a list that displays all items added to Favorites using the "Add to Favorites" button.

function Favorites() {
  const [favList, setFavList] = useState(localStorage.getItem('favorites'));
  return (
    <FavPageContainer>
      {favList}
      {favList.map(listItem => {
        <li>{listItem}</li>
      })}
    </FavPageContainer>
  )
}
function Recipe() {
  let params = useParams();
  const [details, setDetails] = useState({});
  const [activeTab, setActiveTab] = useState('summary');
  const fetchDetails = async () => {
    const data = await fetch(`https://api.spoonacular.com/recipes/${params.name}/information?apiKey=${process.env.REACT_APP_API_KEY}`);
    const detailData = await data.json();
    setDetails(detailData);
  }
  
  useEffect(() => {
    fetchDetails();
  }, [params.name]);

  return (
    <DetailWrapper>
        <h2>{details.title}</h2>
        <img src={details.image} alt="" />

      <Info>
        <ButtonContainer>
          <AddToFavorites details={details}/>
          <Button 
            className={activeTab === 'summary' ? 'active' : ''}
            onClick={() => setActiveTab('summary')}>Nutrition Info
          </Button>
          <Button 
            className={activeTab === 'ingredients' ? 'active' : ''}
            onClick={() => setActiveTab('ingredients')}>Ingredients
          </Button>
          <Button
            className={activeTab === 'instructions' ? 'active' : ''}
            onClick={() => setActiveTab('instructions')}>Instructions
          </Button>
        </ButtonContainer>
        {activeTab === 'instructions' && (
          <div>
            <p dangerouslySetInnerHTML={{__html: details.instructions}}></p>
          </div>
        )}
        {activeTab === 'ingredients' && (
          <ul>
          {details.extendedIngredients &&
            details.extendedIngredients.map((ingredient) => (
              <li key={ingredient.id}> {ingredient.original}</li>
            ))}
          </ul>
        )}
         {activeTab === 'summary' && (
          <div>
            <p dangerouslySetInnerHTML={{__html: details.summary}}></p>
          </div>
        )}
      </Info>
    </DetailWrapper>
  )
}
function AddToFavorites(details) {
  const [active, setActive] = useState(false);
  const [favorites, setFavorites] = useState([]);
  const handleActive = () => {
      setActive(!active);
  };

  const handleFavorites = () => {
    handleActive();
    if(active){
      removeFromFavorites();
    } else if(!active) {
      addToFavorites();
  }
};

  const addToFavorites = () => {
    handleActive();
      setFavorites([...favorites, details]);
      console.log(favorites)
      localStorage.setItem('favorites', JSON.stringify(favorites));
  };
 
return (
  <AddToFavBtn className={active ? 'active' : null} onClick={handleFavorites}>
      {!active ? 'Add to favorites' : 'Remove from favorites'}
      <div>
      <BsFillSuitHeartFill/>
      </div>
  </AddToFavBtn>
)
}

What I've tried to do so far:

  • Pass API data to AddToFavorites as the "details" attribute in the Recipe.
  • Set favorites in AddToFavorites to the default empty array state.
  • Add onClick event in AddToFavorites to add to favorites btn, which calls the AddToFavorites() function.
  • In the AddToFavorites() function I try to permanently update the favorites status by using the spread operator and adding the received details prop (with API data) as a new item to a new copy of the status array and then Store it in local storage.

When I add an item to favorites, I can add one item or multiple times. But when I go to a new recipe and add another item, it deletes the old item and restarts.

I've been looking into it for a few days and trying different things but I can't figure it out.

P粉604669414
P粉604669414

reply all(1)
P粉054616867

This seems to be a good example of shared state. If your Favorites data is managed in one place, you won't have synchronization issues when adding, deleting or displaying it.

I recommend creating a context

import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
} from "react";

const FavoritesContext = createContext({
  favorites: [],
  toggleFavorite: () => {},
  isFavorite: () => false,
}); // default context value

export const FavoritesContextProvider = ({ children }) => {
  const preloadRef = useRef(false);

  const [favorites, setFavorites] = useState(
    JSON.parse(localStorage.getItem("favorites")) ?? []
  );

  // assuming favourites have IDs
  const ids = useMemo(
    () => new Set(favorites.map(({ id }) => id)),
    [favorites]
  );
  const isFavorite = useCallback((id) => ids.has(id), [ids]);

  // sync data on change
  useEffect(() => {
    // skip initial preload
    if (preloadRef.current) {
      localStorage.setItem("favorites", JSON.stringify(favorites));
    }
    preloadRef.current = true;
  }, [favorites]);

  const toggleFavorite = ({ id, image, title, route }) => {
    if (isFavorite(id)) {
      setFavorites((prev) => prev.filter((fav) => fav.id !== id));
    } else {
      setFavorites((prev) => [...prev, { id, image, title, route }]);
    }
  };

  return (
    
      {children}
    
  );
};

// hook helper
export const useFavorites = () => useContext(FavoritesContext);

Then wrap the relevant parts of the application with a context provider, e.g.


  

Use context hooks whenever you need to read or modify Favorites

// read
const { favorites } = useFavorites();

// modify
const { isFavorite, toggleFavorite } = useFavorites();

You can also use any other form of state management, such as Redux.

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!