0

This is a simplified React component that uses helmet to update the link css on runtime:

function App() {
  const [brand, setBrand] = useState('nike')
  return (
    <div className="App">
      <Helmet>
        <link rel="stylesheet" href={getBrandStyle(brand)} />
      </Helmet> 
      <div>other contents here</div>
      <!-- omitted the button components that change the brand state by calling setBrand -->
    </div>
  );
}

I have recently just used react-helmet as a declarative way to change the head tag's child and with the code I wrote above, when switching the css there is momentary lag when the page has no css stylings and then 1 second later the updated css shows up.

Even during the initial load of the page, if I use queryParameters (code above doesn't show the query parameter approach) such as

https://localhost:3000?brandQueryParam=nike

there is 1 second wherein there is no css styling before the brand css shows up.

Can you please let me know what I am missing and how to resolve this?

Steve
  • 11,596
  • 7
  • 39
  • 53
Carlos Jaime C. De Leon
  • 2,476
  • 2
  • 37
  • 53
  • 1
    What you're seeing is called FOUC (Flash of Unstyled Content) -- If you're going to continue down this path you'll probably want to include an intermediate loading page with self-contained styling while the brand CSS is loading. – Steve Feb 10 '22 at 06:39
  • thanks @SteveGomez - you are right, I ended up adding an intermediate loading spinner with setTimeout (not sure if setTimeout is the best solution but that's what's good enough for now). great to know this FOUC, its good to have a word / acronym attached to this scenario :) – Carlos Jaime C. De Leon Feb 22 '22 at 23:46

1 Answers1

0

This is the solution that I came up with, not sure if setTimeout is the best solution so if anyone else knows a better way, please share it.

const brands = {
  nike: 'nike2022',
  adidas: 'adidas2017',
  fila: 'fila2020'
};

function App() {
  const [brand, setBrand] = useState('nike')
  const [isLoading, setIsLoading] = useState(false)
  const changeBrandStyleOnClick = (brand) => {
    setBrand(brand)
    setIsLoading(true)
  }

  return (
    <div className="App">
      <Helmet>
        <link rel="stylesheet" 
              onChangeClientState={(newState, addedTags, removedTags) => setTimeout(() => setIsLoading(false), 1500)}
              href={getBrandStyle(brand)} />
      </Helmet> 
      {isLoading && (
        <Overlay>
          <Spinner/>
        </Overlay>
      )}

      {!isLoading && (
        <>
          {Object.keys(brands).filter(b => b !== brand).map(b =>
            (<Button onClick={() => changeBrandStyleOnClick (b)} value={b}>
            <Logo
              alt="default alt name"
              appearance="default"
              name={b}
              size="small"/>
            </Button>))
          }
          <div>other contents here</div>
        </>
      )}
    </div>
  );
}
Carlos Jaime C. De Leon
  • 2,476
  • 2
  • 37
  • 53