question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Wrapped styled-components don't update on Fast Refresh of imported modules

See original GitHub issue

Bug report

Describe the bug

When a styled component is created by wrapping another styled component, as in:

const Wrapper = styled(AnotherStyledComponent)``;

updates to the wrapped component aren’t properly applied during Fast Refresh, when AnotherStyledComponent is imported from a separate module, and that module exports only React components. More info (and theories) at the end of this issue.

To Reproduce

Minimal reproduction at: https://gitlab.com/andrew.gies.axiom/next-sc-bug The reproduction repo is based on the official example for using styled-components.

Can be run using yarn dev or npm run dev and opening localhost:9000. Open lib/components.js and change the background color of the StyledThing component - notice that components.js is reloaded and re-evaluated by checking the browser console, yet the new styles aren’t applied to the page.

Uncommenting the export const RandomNumber = 5 line will cause the Fast Refresh/HMR behavior to work correctly upon changes to StyledThing.

Expected behavior

When the styles are changed in code, they are updated in the browser after a Fast Refresh/HMR without needing to reload the page.

System information

  • OS: macOS Mojave 10.14.6
  • Browser: Chrome 84.0.4147.125
  • Version of Next.js: 9.5.2
  • Version of Node.js: 12.18.2

Additional context

This bug was introduced in next.js 9.3.7-canary.19 (not reproducible in 9.3.7-canary.18), which leads me to believe that it is an issue with Fast Refresh. (Fast Refresh was enabled by default in canary 19). It is reproducible on the current latest version of next as well (9.5.2).

Styled components can “wrap” other styled components to create extensions of their styles. This doesn’t actually create a component tree that contains a wrapper component and a wrapped component; instead, styled-components creates a new component that duplicates the old component, but with the new styles added. When one of the “wrapped” components changes, the changes are not properly updated if only the “wrapper” is actually being used in component tree.

The below refers specifically to the example in my minimal reproduction repo, above.

For example, running in dev mode and changing the background of StyledThing in components.js will not properly update on the webpage. In the browser console, we can see that components.js is being reloaded and re-evaluated, but index.jsx is never reloaded, and so the updated component is never re-wrapped into Wrapper in index.jsx and inserted into the React tree. If anything that isn’t a React component is exported by components.js, then this issue no longer exists. (However, multiple react components can be exported with the same issue).

My guess is that roughly the following logic is being applied to cause the bug:

  • Fast Refresh is noticing that components.js needs to be reloaded, grabs the new file and re-evaluates it.
  • It sees that the only things exported by this file are react components, so it’ll attempt to update only parts of the existing React tree that are using these components.
  • Since StyledThing doesn’t appear anywhere in the React tree, nothing is updated and index.jsx is not re-run, so the changes are never applied.

However, when something else (like a number) is exported from components.js, the following happens:

  • Fast Refresh is noticing that components.js needs to be reloaded, grabs the new file and re-evaluates it.
  • At least one non-React-component thing is exported, which means it may have effects on files that import it beyond just changes to the React tree.
  • To play it safe, Fast Refresh falls back to the more “traditional” HMR behavior of re-evaluating all modules that import components.js, which includes index.jsx.

The mistake is in the assumption that the only effect a React component can have on a program is if it is inserted into the component tree, and that the component can be entirely ignored if not used in that way. While a mostly reasonable assumption, this breaks in situations like styled-components wrappers where components are used indirectly, having an effect on the program execution without ever being inserted into the tree.

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:8
  • Comments:9 (2 by maintainers)

github_iconTop GitHub Comments

4reactions
DPangerlcommented, Aug 26, 2022

For me fast refresh is working except the wrapped styled component is imported from another file. Upon saving, fast refresh updates the styles in the browser, but the changes are not reflected until I change something else (e.g. comment) or do a refresh.

My config looks like this:

"dependencies": {
    "next": "^12.2.5",
    "react": "^18.0.0",
    "react-dom": "^18.0.0",
    "sharp": "^0.30.1",
    "styled-components": "^5.3.5"
  }
module.exports = {
  compiler: {
    styledComponents: true,
  }
};
1reaction
maaptehcommented, Oct 21, 2020

I will look, nope im using 5.2.0 but have totally unstylled buttons, only in prod build they are back again. After the update to document it is now working https://medium.com/swlh/server-side-rendering-styled-components-with-nextjs-1db1353e915e

Read more comments on GitHub >

github_iconTop Results From Across the Web

Wrapped styled-components don't update on Fast Refresh of ...
When changing a wrapped styled component from another module, react-refresh does not seem to update their children. You require an F5, ...
Read more >
NextJS with styled-components fast refresh not working
js Whenever I change css properties in HeaderStyles.js , the fast refresh works just fine. However, in the case of GlobalComponents.js , I...
Read more >
Releases - styled-components
Updating styled components is usually as simple as npm install . Only major versions have the potential to introduce breaking changes (noted in...
Read more >
Basic Features: Fast Refresh - Next.js
Next.js' Fast Refresh is a new hot reloading experience that gives you instantaneous feedback on edits made to your React components.
Read more >
Complete Guide On How To Use Styled-components In React
js (CSS module) which has done a marvelous job in simplifying this approach for its users. In Next.js, each page/component can have a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found