Gatsby/React:如何防止在更改 display:none 元素的背景图像时发生这种重绘?
Gatsby/React: How to prevent this repaint that occurs when chanding background-image of a display:none element?
已编辑:根据@HMR 的回答,我包含了他的建议并提供了完整的代码
如果我有这样的组件
const wait = ...
cosnt get_new_wallpaper = ... // it changes pool_of_images_fetched
const Wallpaper = () => {
const [background, setBackground] = useState()
const [nextBackground, setNextBackground] = useState()
const [visible, setVisible] = useState('first') // not changed in this example
const [pool_of_images_fetched, setPool_of_images_fetched] = useState([])
const setNewWallpaper = useCallback(async stillMounted => {
const wallpaper = await get_new_wallpaper(
pool_of_images_fetched,
setPool_of_images_fetched
)
stillMounted.value && setBackground(wallpaper)
await wait(2000)
const wallpaper2 = await get_new_wallpaper(
pool_of_images_fetched,
setPool_of_images_fetched
)
stillMounted.value && setNextBackground(wallpaper2)
}, [])
useEffect(() => {
let stillMounted = {value: true}
const init_new_wallpaper = async () => await setNewWallpaper (stillMounted)
init_new_wallpaper()
return function cancel() {
stillMounted.value = false
}
}, [])
return (
<>
<PureFirst background={background} onClick={setNewWallpaper} />
<PureSecond background={nextBackground} onClick={setNewWallpaper} />
</>
)
}
const First = styled.div`
display: ${props => (props.visible === 'first' ? 'unset' : 'none')};
background-image: url('${props => props.background}');
`
const Second = styled.div`
display: ${props => (props.visible === 'second' ? 'unset' : 'none')};
background-image: url('${props => props.background}');
`
const PureFirst = memo(First)
const PureSecond = memo(Second)
当 setNewWallpaper()
改变时 background
我看到 <First>
相应改变,然后等待 2 秒,然后当它改变时 nextBackground
我也看到 <Second>
相应地改变
如您所见,<First>
可见 (display:unset;
),但 <Second>
不可见 (display:none;
)
这里的问题是当<Second>
改变时<First>
被重新绘制,即使<Second>
是看不见的,所以发生的事情是2 秒后 flash
为什么这里没有记住这段代码?
您可以使用 React.memo and use useCallback 将 first 和 second 设为纯组件,以确保 setNewWallpaper 不会在渲染之间更改引用。
我不知道 setNewWallpaper 的依赖项是什么,因为您没有 post 所有代码,所以我假设有 none:
const PureFirst = React.memo(First);
const PureSecond = React.memo(Second);
export const Wallpaper = () => {
const [background, setBackground] = useState();
const [nextBackground, setNextBackground] = useState();
const setNewWallpaper = useCallback(async () => {
setBackground(...);
await wait(2000);
setNextBackground(...);
}, []);
return (
<>
<PureFirst
background={background}
onClick={setNewWallpaper}
/>
<PureSecond
background={nextBackground}
onClick={setNewWallpaper}
/>
</>
);
};
关闭问题,最后闪现是由于打开了开发者工具导致的,然后点击了禁用缓存
没有它,不重绘
已编辑:根据@HMR 的回答,我包含了他的建议并提供了完整的代码
如果我有这样的组件
const wait = ...
cosnt get_new_wallpaper = ... // it changes pool_of_images_fetched
const Wallpaper = () => {
const [background, setBackground] = useState()
const [nextBackground, setNextBackground] = useState()
const [visible, setVisible] = useState('first') // not changed in this example
const [pool_of_images_fetched, setPool_of_images_fetched] = useState([])
const setNewWallpaper = useCallback(async stillMounted => {
const wallpaper = await get_new_wallpaper(
pool_of_images_fetched,
setPool_of_images_fetched
)
stillMounted.value && setBackground(wallpaper)
await wait(2000)
const wallpaper2 = await get_new_wallpaper(
pool_of_images_fetched,
setPool_of_images_fetched
)
stillMounted.value && setNextBackground(wallpaper2)
}, [])
useEffect(() => {
let stillMounted = {value: true}
const init_new_wallpaper = async () => await setNewWallpaper (stillMounted)
init_new_wallpaper()
return function cancel() {
stillMounted.value = false
}
}, [])
return (
<>
<PureFirst background={background} onClick={setNewWallpaper} />
<PureSecond background={nextBackground} onClick={setNewWallpaper} />
</>
)
}
const First = styled.div`
display: ${props => (props.visible === 'first' ? 'unset' : 'none')};
background-image: url('${props => props.background}');
`
const Second = styled.div`
display: ${props => (props.visible === 'second' ? 'unset' : 'none')};
background-image: url('${props => props.background}');
`
const PureFirst = memo(First)
const PureSecond = memo(Second)
当 setNewWallpaper()
改变时 background
我看到 <First>
相应改变,然后等待 2 秒,然后当它改变时 nextBackground
我也看到 <Second>
相应地改变
如您所见,<First>
可见 (display:unset;
),但 <Second>
不可见 (display:none;
)
这里的问题是当<Second>
改变时<First>
被重新绘制,即使<Second>
是看不见的,所以发生的事情是2 秒后 flash
为什么这里没有记住这段代码?
您可以使用 React.memo and use useCallback 将 first 和 second 设为纯组件,以确保 setNewWallpaper 不会在渲染之间更改引用。
我不知道 setNewWallpaper 的依赖项是什么,因为您没有 post 所有代码,所以我假设有 none:
const PureFirst = React.memo(First);
const PureSecond = React.memo(Second);
export const Wallpaper = () => {
const [background, setBackground] = useState();
const [nextBackground, setNextBackground] = useState();
const setNewWallpaper = useCallback(async () => {
setBackground(...);
await wait(2000);
setNextBackground(...);
}, []);
return (
<>
<PureFirst
background={background}
onClick={setNewWallpaper}
/>
<PureSecond
background={nextBackground}
onClick={setNewWallpaper}
/>
</>
);
};
关闭问题,最后闪现是由于打开了开发者工具导致的,然后点击了禁用缓存
没有它,不重绘