1

I want to toggle each of the item that I clicked on but Its keeps toggling all the Items. Using the useContext api

            import React, { useState, useEffect } from "react";
        
        const MyContext = React.createContext({
          addToFavorites: () => {},
          likeHandler: () => {},
          fetchRequest: () => {},
        });
        
        export const MyContextProvider = (props) => {
          const [favorites, setfavorites] = useState([]);
          const [toggle, setToggle] = useState(false);
          const [items, setItems] = useState([]);
        
          const fetchRequest = async () => {
            const api_Key = "oLfD9P45t23L5bwYmF2sib88WW5yZ8Xd7mkmhGSy";
            const response = await fetch(
              `https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos? 
                sol=50&api_key=${api_Key}`
            );
            const data = await response.json();
            const allItems = data.photos.map((item) => {
              return {
                id: item.id,
                title: item.camera.full_name,
                img: item.img_src,
                date: item.rover.launch_date,
                like: false,
              };
            });
            setItems(allItems);
          };
        
          const likeHandler = (item) => {
            const found = items.find((x) => x.id === item.id);
            setToggle((found.like = !found.like));
        
            console.log(found); //this logs the particular item that is clicked on
          };
          return (
            <MyContext.Provider
              value={{
                likeHandler,
                fetchRequest,
                toggleLike: toggle,
                data: items,
              }}
            >
              {props.children}
            </MyContext.Provider>
          );
        };
        
        export default MyContext;
        

I also have a NasaCard component where I call the likeHandler function and the toggle state, onClick of the FavoriteIcon from my context.And I pass in the toggle state to a liked props in my styled component to set the color of the favorite Icon

        import {
          Container,
          Image,
          Name,
          InnerContainer,
          Titlecontainer,
          Date,
          FavouriteContainer,
          FavouriteIcon,
          ImageContainer,
          SocialContainer,
        } from "./index";
        import MyContext from "../../Context/store";
        import React, { useState, useEffect, useContext } from "react";
        
        const NasaCards = (props) => {
          const { likeHandler, toggleLike } = useContext(MyContext);
        
          return (
            <Container>
              <InnerContainer>
                <ImageContainer>
                  <Image src={props.Image} alt="" />
                </ImageContainer>
        
                <Titlecontainer>
                  <Name>{props.title}</Name>
                  <Date>{props.date}</Date>
                  <FavouriteContainer>
                    <FavouriteIcon
                      liked={toggleLike}
                      onClick={() => {
                        likeHandler({
                          id: props.id,
                          title: props.title,
                          Image: props.Image,
                        });
                      }}
                    />
                  
              </InnerContainer>
            </Container>
          );
        };
        
        export default NasaCards;
    


   


 
Wesle6
  • 31
  • 3

1 Answers1

2

I think you're making this a little more complicated than it needs to be. For starters you are using a single boolean toggle state for all the context consumers, and then I think you're mixing your like property on the items state array with the toggle state.

The items array objects have a like property, so you can simply toggle that in the context, and then also use that property when mapping that array.

MyContextProvider - Map the items state to a new array, updating the like property of the matching item.

const likeHandler = (item) => {
  setItems(items => items.map(
    el => el.id === item.id
      ? { ...el, like: !el.like }
      : el
  ));
    
  console.log(item); // this logs the particular item that is clicked on
};

NasaCards - Use item.like property for the liked prop on FavouriteIcon and pass the entire props object to the likeHandler callback.

const NasaCards = (props) => {
  const { likeHandler } = useContext(MyContext);
    
  return (
    <Container>
      <InnerContainer>
        <ImageContainer>
          <Image src={props.Image} alt="" />
        </ImageContainer>
    
        <Titlecontainer>
          <Name>{props.title}</Name>
          <Date>{props.date}</Date>
          <FavouriteContainer>
            <FavouriteIcon
              liked={props.like} // <-- use like property
              onClick={() => {
                likeHandler(props); // <-- props has id property
              }}
            />
          </FavouriteContainer>
        </Titlecontainer?
      </InnerContainer>
    </Container>
  );
};
Drew Reese
  • 165,259
  • 14
  • 153
  • 181