recherche

Maison  >  Questions et réponses  >  le corps du texte

Comment mettre à jour de manière immuable un tableau et le stocker dans le stockage local dans React ?

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 :

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粉604669414P粉604669414265 Il y a quelques jours442

répondre à tous(1)je répondrai

  • P粉054616867

    P粉0546168672024-04-03 09:03:17

    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.

    répondre
    0
  • Annulerrépondre