reactjsimagehoverlistitem

Show different images for each list item with React onMouseEnter and onMouseLeave


I'm new with React and before writing here I looked everywhere for my problem: I have a list with four items, and I want to show on hover different image for each item.

const [isShown, setIsShown] = useState(false);
  return (
    <div className="App">
      <ul>
        <li>
          <a
            onMouseEnter={() => setIsShown(true)}
            onMouseLeave={() => setIsShown(false)}
            href="/"
          >
            Item1
          </a>
          {isShown && (
            <div style={{ width: `width: 300px` }}>
              <img
                className="image"
                src="https://images.pexels.com/photos/1145720/pexels-photo-1145720.jpeg?auto=compress&cs=tinysrgb&dpr=3&h=750&w=1260"
                alt=""
              />
            </div>
          )}
        </li>
         ...

I have used this procedure for each <li> but no matter which item I hover, all images are shown.

Can someone help me? Thank you

Here the example

Update

I tried to use arrays as suggested by John but I am doing something wrong because the images are shown all together:

const projects = [
  { id: 1, title: "Item1" },
  { id: 2, title: "Item2" },
  { id: 3, title: "Item3" },
  { id: 4, title: "Item4" }
];

const images = [
  {image: "https://placekitten.com/800/600", id: 1},
  {image: "https://placekitten.com/800/600", id: 2},
  {image: "https://placekitten.com/800/600", id: 3},
  {image: "https://placekitten.com/800/600", id: 4},
];
function Portfolio(props) {
  const [isShown, setIsShown] = useState(false);

  return (
    <section>
      <div className="wrap">
        <div className="container">
          <ul className="wrap">
            {props.projects.map((project, image) => (
              <li key={project.id}>
                <a
                  onMouseEnter={() => setIsShown(true)}
                  onMouseLeave={() => setIsShown(false)}
                  href="/"
                >
                  {project.title}
                </a>
                {isShown && (
                  <img key={image.id} src={image} style={{position: `absoulte` }}/>
                )}
              </li>
            ))}
          </ul>
        </div>
      </div>
    </section>
  );

Solution

  • This is because you're using the same flag isShown to show all of the images. What you should do is change it from a boolean to a int and assign an index to it.

    onMouseEnter={() => setIsShown(1)}
    onMouseLeave={() => setIsShown(0)}
    
    ..
    
    onMouseEnter={() => setIsShown(2)}
    onMouseLeave={() => setIsShown(0)}
    
    ... etc
    

    So for each image you'd have something like this

    isShown === 1 && (
      ...code
    )
    
    isShown === 2 && (
      ...code
    )
    

    This way each image will depend on a specific value, making each of them independent.

    A small suggestion. Since the code you're printing is redundant, I suggest you create an array of your items and map them on the render instead of printing each item manually. Let me know if you have more questions about this.


    Update:

    I think there was a misunderstanding in what my suggestion was. I'm adjusting your code now, maybe now it will much clearer.

    function Portfolio(props) {
      const [isShown, setIsShown] = useState(false);
      const projects = [
        { id: 1, title: "Item1", image: "https://placekitten.com/800/600" },
        { id: 2, title: "Item2", image: "https://placekitten.com/800/600" },
        { id: 3, title: "Item3", image: "https://placekitten.com/800/600" },
        { id: 4, title: "Item4", image: "https://placekitten.com/800/600" }
      ];
    
      return (
        <section>
          <div className="wrap">
            <div className="container">
              <ul className="wrap">
                {projects.map((project, image) => (
                  <li key={project.id}>
                    <a
                      onMouseEnter={() => setIsShown(project.id)}
                      onMouseLeave={() => setIsShown(0)}
                      href="/"
                    >
                      {project.title}
                    </a>
                    {isShown === project.id && (
                      <img src={project.image} style={{position: `absoulte` }}/>
                    )}
                  </li>
                ))}
              </ul>
            </div>
          </div>
        </section>
      );
    }
    

    Let me know if you have any questions.