当 Chrome Dev Tools 打开时图像在 Styled Component 内重新渲染

Images Rerendering inside Styled Component when Chrome Dev Tools is open

这有点奇怪,不确定为什么会这样。

安装组件时,我调用一个函数,该函数在我的应用程序中发出 HTTP 请求以获取对象数组。然后我在 map 方法中更新 3 个状态。

enquiries - 这只是来自 HTTP 请求的响应 activeProperty - 定义当前活动的对象 ID channelDetails - 解析一些响应数据以用作传递给子组件的道具。

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();
}, []);

然后我 return 一个子组件 ChannelList 使用样式化组件向元素添加样式并呈现子元素。

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

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

ChannelList 组件中,我映射到 enquiries 状态并呈现 ChannelListItem 组件,该组件在数组中的对象索引上分配了一个键,并接受 channelDetails 状态和 onClick 处理程序。

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..."
      )}
    </>
  );

ChannelListItem 组件中,我根据 channelDetails 状态

details 属性渲染了两张图像
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>
  );
};

现在,只要打开 chrome 开发工具 window 并单击不同的 ChannelListItems 图像 blink/rerender,问题就会出现。我原以为 diff 算法会在这里启动而不是重新渲染图像,因为它们是相同的图像?

但似乎 styled-components 会在您每次单击 ChannelListItem 时添加一个新的 class,因此它会重新渲染图像。但只有当开发工具 window 打开时?

这是为什么?有解决办法吗?

我可以使用内联样式而不是 styled-components 并且它按预期工作,但我想看看是否有解决此问题的方法而不删除 styled-components

我有一个CODESANDBOX你们自己查

我认为这与禁用缓存的设置有关(见图像中的红色标记)

希望对您有所帮助。

如果您在网络选项卡的开发工具中重新激活 cache,问题就会消失。

所以问题就变成了为什么浏览器在禁用缓存时重新获取图像 ;)

这仅仅是因为 dom 更改,所以浏览器会按照您提到的 class 更改重新呈现它。

因此 class 发生变化是因为组件发生了变化。 您在每次渲染时创建一个新组件。

一个简单的修复:

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;