Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Themed component not updating with new values (Next.js SSR) #2880

Closed
leerob opened this issue Nov 18, 2019 · 11 comments
Closed

Themed component not updating with new values (Next.js SSR) #2880

leerob opened this issue Nov 18, 2019 · 11 comments

Comments

@leerob
Copy link

leerob commented Nov 18, 2019

Environment

System:

  • OS: macOS Mojave 10.14.6
  • CPU: (8) x64 Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
  • Memory: 906.16 MB / 16.00 GB
  • Shell: 5.3 - /bin/zsh

Binaries:

  • Node: 10.15.0 - ~/.nvm/versions/node/v10.15.0/bin/node
  • Yarn: 1.16.0 - /usr/local/bin/yarn
  • npm: 6.4.1 - ~/.nvm/versions/node/v10.15.0/bin/npm

npmPackages:

  • babel-plugin-styled-components: 1.10.6 => 1.10.6
  • styled-components: 5.0.0-rc.2 => 5.0.0-rc.2

Reproduction

leerob/leerob.io#130
https://leerob-git-use-dark-mode.leerob1.now.sh/

Steps to reproduce

  1. Load the page.
  2. Observe the styles being off on initial page load.

Expected Behavior

All of the styles should display correctly on page load.
image

Actual Behavior

Some work, but others do not.
image

Digging in deeper at a specific example, look at the TimelineStep.

It uses a value from the theme for the border color.

        border: 10px solid
            ${(props) => {
                console.log(props.theme.secondary);

                return props.theme.secondary;
            }};

If I put a console log inside of the component. I get two different values depending on whether I'm on the server or client. This makes sense.

In my terminal output, it's white. In my browser console, it's dark grey. This is because Next is serving up the initial styles through_document.js on page load and it's server-side rendered. The issue is that the styled-component is not updating.

If I log out the theme in the component, I can confirm it's getting the new dark theme. The only way I can get the component to recognize the changes is to force an arbitrary re-render like so:

const themeContext = useContext(ThemeContext);
console.log(themeContext);

const [test, setTest] = React.useState('test');

React.useEffect(() => {
    setTest('new');
}, []);


...
...


<StyledTimeline key={test}>

Another way to observe this behavior is to toggle the theme. This correctly updates the components.
2019-11-17 18 51 09

@edenstrom
Copy link

Sadly, I have the same behaviour in a Gatsby project with styled-components. Tried SC 4.2 => 5.0.0-rc2.

Maybe #2629 is relevant?

As you found re-rendering everything makes it work, but makes for some ugly code.

@leerob
Copy link
Author

leerob commented Nov 18, 2019

Well, at least I'm not crazy. This one has been puzzling me.

@edenstrom
Copy link

edenstrom commented Nov 18, 2019

Yes, I can't really see any logic behind it neither. Some components update with the correct theme, some doesn't.

I'm using styled-system if that changes anything.

I'll probably disable the dark theme until I can find a better solution.

EDIT: in the image below, light mode is server-rendered, dark mode is client-rendered.

2019-11-18 at 15 24

@leerob
Copy link
Author

leerob commented Dec 17, 2019

Found a workaround here -> https://brianlovin.com/overthought/adding-dark-mode-with-next-js

// Providers.tsx
import { lightTheme, darkTheme } from '../Theme';

export default ({ children }) => {
  const { value } = useDarkMode(false, { storageKey: null, onChange: null })
  const theme = value ? darkTheme : lightTheme

  const [mounted, setMounted] = React.useState(false)

  React.useEffect(() => {
    setMounted(true)
  }, [])

  // prevents ssr flash for mismatched dark mode
  if (!mounted) return null

  return (
    <ThemeProvider theme={theme}>
      {children}
    </ThemeProvider>
  );
}

@brianlovin
Copy link

Unfortunately this solution breaks things like server-side generated meta tags, used for generating social media previews on links (and general SEO best practices).

If I remove the hack I found here: #2880 (comment) we have confirmed that styled-components breaks, but social media cards / SEO issues are resolved.

@quantizor
Copy link
Contributor

I can't tell if this is still an issue

@leerob
Copy link
Author

leerob commented Dec 30, 2019 via email

@quantizor
Copy link
Contributor

Ok, do you have a more current reproduction? I see the linked issue in the OP is closed.

@leerob
Copy link
Author

leerob commented Dec 30, 2019

Yep, sorry about that. I ended up closing that PR and turning on the dark mode by default.

Here's a new PR that adds the dark theme toggle back in. Should be able to reproduce from here.

leerob/leerob.io#135
https://leerob-git-use-dark-mode-toggle.leerob1.now.sh/

@quantizor
Copy link
Contributor

@mohsen1
Copy link

mohsen1 commented Jan 14, 2020

Setting visibility to hidden is not the best solution IMO. You can use native HTML capabilities for requesting dark theme stylesheet from the server.

<link href="default.css" rel="stylesheet">
<link href="dark.css" rel="stylesheet" media="(prefers-color-scheme: dark)">

Styled Components should render the same class names if your theme objects are having identical structures (property names and tree structure)

How you add those <link> elements to your Next.js build is something I'm not really familiar with because I haven't used Next.js much.

/cc @brianlovin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants