Search code examples
reactjsreact-hooksgatsbyrepaintmemoization

Gatsby/React: How to prevent this repaint that occurs when chanding background-image of a display:none element?


EDITED: Based on answer from @HMR I include his suggestions and provide the complete code

If I have a component such as this

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)

When setNewWallpaper() changes background I see <First> changing accordingly, then 2s of wait, and then when it changes nextBackground I also see <Second> changing accordingly

As you can see, <First> is seen (display:unset;) but <Second> is unseen (display:none;)

The problem here is that <First> gets repainted when <Second> is changed, even though <Second> is unseen, so what happens is a flash in the website after these 2 seconds

Why is this code not memoized here?


Solution

  • Closing the question, at the end the flash was caused by having the developer tools opened and with that, the disable cache clicked

    Without it, no repaint