Image of some items is not updated when modifying the list order

Asked

Viewed 29 times

0

I’m having trouble keeping my images in the right position. I have a list of images, but when I click on the filter to reverse the order, some images keep their position.

For better understanding I made a very clean and easy to understand example that simulates a similar problem, with the "same structure" of my projects, in the Codesandbox.

const api = [
  {
    name: "Elephant",
    url:
      "https://i.pinimg.com/originals/1e/06/e1/1e06e107f0ca520aed316957b685ef5c.jpg"
  },
  {
    name: "Wallpaper Windoes",
    url: "https://img.ibxk.com.br/2015/07/23/23170425700729.jpg?w=328"
  },
  { name: "No image", url: "" },
  { name: "Tiger", url: "https://www.htmlecsspro.com/exemple/img/imagem.jpg" },
  {
    name: "Lion",
    url:
      "https://blogmedia.evbstatic.com/wp-content/uploads/wpmulti/sites/18/2014/07/24025147/6BaVde_t20_VKbpQ7-e1527130375674.jpg"
  },
  { name: "No image 2", url: "" },
  {
    name: "Google",
    url:
      "https://tecnoblog.net/wp-content/uploads/2020/03/google-imagens-700x394.jpg"
  }
];

function App() {
  const [itemsList, setItemsList] = React.useState([]);
  const [isInverted, setIsInverted] = React.useState(false);

  function reverseAction() {
    setIsInverted(isInverted ? false : true);
    setItemsList(api.reverse());
  }

  React.useEffect(() => {
    setItemsList(api);
  }, []);

  return (
    <div>
      <button onClick={reverseAction}>Reverse</button>
      <p>{isInverted ? "true" : "false"}</p>
      {itemsList.map((item, index) => (
        <Cards key={index} item={item} />
      ))}
    </div>
  );
}

const IMG_DEFAULT = 'https://www.luzeoliveira.com.br/index/wp-content/uploads/2017/07/default.png';

function Cards({ item }) {
  const [img, setImg] = React.useState(IMG_DEFAULT);

  //Os itens tem uma imagem padrão, mas a imagem é alterada se o item tiver sua propria imagem
  React.useEffect(() => {
    if (item.url.length > 1) {
      setImg(item.url);
    }
  }, []);

  //se ocorrer erro ao carregar a imagem do item, então volta para a imagem padrão
  function onErrorImg() {
    setImg(IMG_DEFAULT);
  }

  return (
    <div>
      <p>{item.name}</p>
      <img style={{height: 200 }} src={img} alt="img" onError={onErrorImg} />
    </div>
  );
}

ReactDOM.render(<App /> , document.querySelector("#app"));
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>

<div id="app"></div>

  • You have two problems, both are in your useEffect. 1) no dependency array. 2) you only update the state if the item has URL, you need to update anyway: const url = item.url === '' ? hlp.IMG_DEFAULT : item.url; and setImg(url);

  • And you need to put the relevant code in the question, otherwise it will be closed. You may have a link to the Codesandbox, but the question should not depend on something external to answer. Read more at I can only show a link to my website with problems?

  • I will put the code. But since there are several components of different files to form the logic, I thought it would be closed by exercise of information. And on the useEffect I’ve put dependency ray, I’ve put Return and literally every variation that useEffect accepts. I will check the IF solution with Else

  • 2

    Yes, it’s a lot of code. So it’s important to play a [mcve]. If you put some console.log, would realize that the problem is in the component Card, then it could simplify the code well. The correction is here, if you don’t understand my first comment.

  • Yes, I checked and corrected three projects. I’ll add the wrong part of the code to the question just to leave it open in case other people have the same problem. But on the issue, I found that I never used the received props in the component as useEffect arguments, I thought useEffect only monitored changes in the states of its own component. But now with it monitoring the props, the updates get much more accurate. Thank you very much.

1 answer

3


I see two problems in the example you created:

  • The useEffect in the <Card> has a wrong dependency array.

Before editing in the question, there was no dependency array, so useEffect was executed on every render. After editing, you placed [], which causes it to run only the first time, so the images no longer exchange.

The right thing would be [item.url], because you want to update the image whenever it changes:

useEffect(() => {
    //...
}, [item.url]);
  • Your if, in the useEffect of <Card>, does not update the image when the item does not have a URL ('').

You should put the default URL in this case. Therefore, before its edition in the question, all images changed places correctly, with the exception of those without image.

To fix this, simply add the default image if it has no URL:

useEffect(() => {
    const url = item.url === '' ? IMG_DEFAULT : item.url;
    setImg(url);
}, [item.url]);

The corrected example looks like this:

const api = [
  {
    name: "Elephant",
    url:
      "https://i.pinimg.com/originals/1e/06/e1/1e06e107f0ca520aed316957b685ef5c.jpg"
  },
  {
    name: "Wallpaper Windoes",
    url: "https://img.ibxk.com.br/2015/07/23/23170425700729.jpg?w=328"
  },
  { name: "No image", url: "" },
  { name: "Tiger", url: "https://www.htmlecsspro.com/exemple/img/imagem.jpg" },
  {
    name: "Lion",
    url:
      "https://blogmedia.evbstatic.com/wp-content/uploads/wpmulti/sites/18/2014/07/24025147/6BaVde_t20_VKbpQ7-e1527130375674.jpg"
  },
  { name: "No image 2", url: "" },
  {
    name: "Google",
    url:
      "https://tecnoblog.net/wp-content/uploads/2020/03/google-imagens-700x394.jpg"
  }
];

function App() {
  const [itemsList, setItemsList] = React.useState([]);
  const [isInverted, setIsInverted] = React.useState(false);

  function reverseAction() {
    setIsInverted(isInverted ? false : true);
    setItemsList(api.reverse());
  }

  React.useEffect(() => {
    setItemsList(api);
  }, []);

  return (
    <div>
      <button onClick={reverseAction}>Reverse</button>
      <p>{isInverted ? "true" : "false"}</p>
      {itemsList.map((item, index) => (
        <Cards key={index} item={item} />
      ))}
    </div>
  );
}

const IMG_DEFAULT = 'https://www.luzeoliveira.com.br/index/wp-content/uploads/2017/07/default.png';

function Cards({ item }) {
  const [img, setImg] = React.useState(IMG_DEFAULT);

  //Os itens tem uma imagem padrão, mas a imagem é alterada se o item tiver sua propria imagem
  React.useEffect(() => {
    const url = item.url === '' ? IMG_DEFAULT : item.url;
    setImg(url);
  }, [item.url]);

  //se ocorrer erro ao carregar a imagem do item, então volta para a imagem padrão
  function onErrorImg() {
    setImg(IMG_DEFAULT);
  }

  return (
    <div>
      <p>{item.name}</p>
      <img style={{height: 200 }} src={img} alt="img" onError={onErrorImg} />
    </div>
  );
}

ReactDOM.render(<App /> , document.querySelector("#app"));
<script crossorigin src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>

<div id="app"></div>

Browser other questions tagged

You are not signed in. Login or sign up in order to post.