Comment mettre à jour de manière immuable un tableau et le stocker dans le stockage local dans React ?
P粉604669414
P粉604669414 2024-04-02 09:51:18
0
1
406

Je crée une application de recettes. Je souhaite que l'utilisateur puisse ajouter des recettes à une liste de favoris. Il y a 3 composants React impliqués. Recettes, ajouter aux favoris et favoris.

Le composant Recette affiche divers détails sur la recette sélectionnée.

Le composant AddToFavorites est un bouton rendu dans le composant Recipe.

Le composant Favoris est une liste qui affiche tous les éléments ajoutés aux Favoris à l'aide du bouton « Ajouter aux Favoris ».

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>
)
}

Ce que j'ai essayé jusqu'à présent :

  • Transmettez les données de l'API à AddToFavorites en tant qu'attribut "détails" dans la recette.
  • Définissez les favoris dans AddToFavorites par défaut sur un tableau vide.
  • Ajoutez l'événement onClick dans AddToFavorites à ajouter aux favoris btn, qui appelle la fonction AddToFavorites().
  • Dans la fonction AddToFavorites(), j'essaie de mettre à jour de manière permanente l'état des favoris en utilisant l'opérateur de propagation et en ajoutant l'accessoire de détails reçu (avec les données API) en tant que nouvel élément à une nouvelle copie du tableau d'état, puis stocké dans le stockage local.

Lorsque j'ajoute un élément aux favoris, je peux ajouter un élément ou plusieurs fois. Mais lorsque je consulte une nouvelle recette et que j'ajoute un autre élément, il supprime l'ancien élément et redémarre.

J'y réfléchis depuis quelques jours et j'ai essayé différentes choses mais je n'arrive pas à comprendre.

P粉604669414
P粉604669414

répondre à tous(1)
P粉054616867

Cela semble être un bon exemple d'état partagé. Si vos données Favoris sont gérées au même endroit, vous n'aurez pas de problèmes de synchronisation lors de l'ajout, de la suppression ou de l'affichage.

Je recommande de créer un contexte

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);

Ensuite, enveloppez les parties pertinentes de l'application avec un fournisseur de contexte, comme


  

Chaque fois que vous avez besoin de lire ou de modifier des favoris, utilisez des crochets contextuels

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

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

Vous pouvez également utiliser toute autre forme de gestion d'état, comme Redux.

Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal