Ad

Images Rerendering Inside Styled Component When Chrome Dev Tools Is Open

- 1 answer

This is a bit of a strange one and not sure why it's happening exactly.

When the component mounts, I call a function that in my application makes an HTTP request to get an array of Objects. Then I update 3 states within a map method.

enquiries - Which is just the response from the HTTP request activeProperty - Which defines which object id is current active channelDetails - parses some of the response data to be used as a prop to pass down to a child component.

const [enquiries, setEnquiries] = useState({ loading: true });
const [activeProperty, setActiveProperty] = useState();
const [channelDetails, setChannelDetails] = useState([]);

const getChannels = async () => {
  // In my actual project,this is an http request and I filter responses
  const response = await Enquiries;
  const channelDetailsCopy = [...channelDetails];
  setEnquiries(
    response.map((e, i) => {
      const { property } = e;
      if (property) {
        const { id } = property;
        let tempActiveProperty;
        if (i === 0 && !activeProperty) {
          tempActiveProperty = id;
          setActiveProperty(tempActiveProperty);
        }
      }
      channelDetailsCopy.push(getChannelDetails(e));
      return e;
    })
  );
  setChannelDetails(channelDetailsCopy);
};

useEffect(() => {
  getChannels();
}, []);

Then I return a child component ChannelList that uses styled components to add styles to the element and renders child elements.

const ChannelList = ({ children, listHeight }) => {
  const ChannelListDiv = styled.div`
    height: ${listHeight};
    overflow-y: scroll;
    overflow-x: hidden;
  `;

  return <ChannelListDiv className={"ChannelList"}>{children}</ChannelListDiv>;
};

Inside ChannelList component I map over the enquiries state and render the ChannelListItem component which has an assigned key on the index of the object within the array, and accepts the channelDetails state and an onClick handler.

return (
    <>
      {enquiries &&
      enquiries.length > 0 &&
      !enquiries.loading &&
      channelDetails.length > 0 ? (
        <ChannelList listHeight={"380px"}>
          {enquiries.map((enquiry, i) => {
            return (
              <ChannelListItem
                key={i}
                details={channelDetails[i]}
                activeProperty={activeProperty}
                setActiveProperty={id => setActiveProperty(id)}
              />
            );
          })}
        </ChannelList>
      ) : (
        "loading..."
      )}
    </>
  );

In the ChannelListItem component I render two images from the details prop based on the channelDetails state

const ChannelListItem = ({ details, setActiveProperty, activeProperty }) => {
  const handleClick = () => {
    setActiveProperty(details.propId);
  };

  return (
    <div onClick={() => handleClick()} className={`ChannelListItem`}>
      <div className={"ChannelListItemAvatarHeads"}>
        <div
          className={
            "ChannelListItemAvatarHeads-prop ChannelListItemAvatarHead"
          }
          style={{
            backgroundSize: "cover",
            backgroundImage: `url(${details.propertyImage})`
          }}
        />
        <div
          className={
            "ChannelListItemAvatarHeads-agent ChannelListItemAvatarHead"
          }
          style={{
            backgroundSize: "cover",
            backgroundImage: `url(${details.receiverLogo})`
          }}
        />
      </div>
      {activeProperty === details.propId ? <div>active</div> : null}
    </div>
  );
};

Now, the issue comes whenever the chrome dev tools window is open and you click on the different ChannelListItems the images blink/rerender. I had thought that the diff algorithm would have kicked in here and not rerendered the images as they are the same images?

But it seems that styled-components adds a new class every time you click on a ChannelListItem, so it rerenders the image. But ONLY when the develop tools window is open?

Why is this? Is there a way around this?

I can use inline styles instead of styled-components and it works as expected, though I wanted to see if there was a way around this without removing styled-components

I have a CODESANDBOX to check for yourselves

Ad

Answer

If you re-activate cache in devtool on network tab the issue disappear.

So the question becomes why the browser refetch the image when cache is disabled ;)

It is simply because the dom change so browser re-render it as you mentioned it the class change.

So the class change because the componetn change. You create a new component at every render.

A simple fix:

import React from "react";
import styled from "styled-components";

const ChannelListDiv = styled.div`
    height: ${props => props.listHeight};
    overflow-y: scroll;
    overflow-x: hidden;
`;


const ChannelList = ({ children, listHeight }) => {
  return <ChannelListDiv listHeight={listHeight} className={"ChannelList"}>{children}</ChannelListDiv>;
};

export default ChannelList;
Ad
source: stackoverflow.com
Ad