当 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;
这有点奇怪,不确定为什么会这样。
安装组件时,我调用一个函数,该函数在我的应用程序中发出 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;