Importing/exporting styled components in React causes invalid hook calls - reactjs

I am working on a React project (react#18.2.0, styled-components#5.1.1) that has been set up to use styled-components so that commonly used components are exported from a common/styled.js file, but that causes a great amount of invalid hook call errors.
Right now, it looks something like this:
export const ExampleButton = styled.button`
color: white;
`;
And then those styled componets are imported where needed, like this:
import { ExampleButton, SomeComponent, AnotherComponent } from '../common.styled';
I know they invalid hook calls are caused by this export/import setup, because the error message for one particular styled component goes away when I remove it from common/styled.js and instead paste it locally everywhere it's needed, so that instead of this:
import { ExampleButton } from '../common.styled';
const ExampleComponent = () => {
return (
<div>
<ExampleButton>Hello</ExampleButton>
</div>
);
};
I do this:
import styled from 'styled-components';
const ExampleComponent = () => {
const ExampleButton = styled.button`
color: white;
`;
return (
<div>
<ExampleButton>Hello</ExampleButton>
</div>
);
};
So that works, but it's not really a viable solution, because I would have to paste the same code everywhere, not just ExampleComponent, and doing that for the whole project would result in a massive amount of code repetition.
What is the right way to create a solution similar to common/styled.js here in a way that doesn't break the Rules of Hooks?

It seems that there had been an issue between some older versions of styled-components and React 18 that have been solved in v5.3.1.
https://github.com/styled-components/styled-components/pull/3564
Maybe upgrading styled-components to v5.3.1 or higher would solve the issue.

Related

is there anything wrong with using classnames with styled components?

Is there anything wrong with using classnames within styled components like so:
export const StyledNav = styled.nav`
background-color: ${({ theme }) => theme.backgroundSecondary};
.logo-container {
width: 201px;
img {
padding: 28px 24.47px 26.78px 24px;
}
}
`;
here I used the classname logo-container rather than making an entire new styled component for that.
You can use nesting and SCSS-like combinations
See their official doc page, and refer to Pseudoelements, pseudoselectors, and nesting section.
It shows an example where, just as your snippet, one component is declared which contains nested selectors and class names.
There's nothing wrong with this approach, and it might actually be more efficient than creating every single element as a styled component.

TypeError: Object(...) is not a function in React when importing JSS file using material UI

I am trying to import my jss file to React component (.jsx) and I have this error :
I looked through related questions and I tried all solutions, mostly about updating versions of material-ui. Here is my package.json file:
the way I write jss file :
import { makeStyles } from '#material-ui/styles';
const useStyles = makeStyles((theme) => ({
root:
{
margin: '10px'
}
}));
export default useStyles;
And jsx file :
import React from 'react';
import DateBar from './DateBar';
import Grid from '#material-ui/core/Grid';
import useStyles from './Board.jss';
export default function Board()
{
const classes = useStyles();
return(
...
Am I missing something or Do I need additional packages for using jsx and jss in React?
I have been trying all the solutions but didn't work..
Note: When I put the code inside of Jss into Jsx file, code works fine. Importing/Exporting might be an issue..
Edit: Still couldn't fix even though I created a new app and installed dependancies from the beginning..

weird issues when using styled-component in npm packages

I'm trying to create a npm package - a UI component.
Let's say I have a project called fancy-web, and the npm package called fancy-components.
In fancy-web, I include in package.json
"fancy-components": "^0.0.1"
( In other words, fancy-web will consume fancy-components ).
In fancy-web, I have
// ...
import { ThemeProvider } from 'styled-components';
import { Testing } from 'fancy-components';
// ...
return (
<ThemeProvider theme={theme}>
<Testing />
</ThemeProvider>
)
The problem is here
In my fancy-components Testing component, if I'm doing
If I'm doing something trivial like this in the Testing component, I will get an error
Uncaught Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
---
import React from 'react';
import styled from 'styled-components';
const Container = styled.div`
margin-top: 40px;
`;
function Testing(props: Props): JSX.Element {
return (
<Container>
<div>Testing</div>
</Container>
);
}
export default Testing;
However, the following works if my "Testing" component just like that.
The following is the `Testing` code
---
import React from 'react';
import styled from 'styled-components';
function Testing(props: Props): JSX.Element {
return (
<div>Testing</div>
);
}
export default Testing;
Not sure what is wrong here and really appreciated of any help.
It turns out because I'm doing linking which cause the issues. After I push it out instead of doing linking, everything works fine.

React app using Material UI hooks not showing styling in production

I have a react app using Material UI (v4). In my development environment it all works fine.
In production the styling does not seem to be applied.
I have read about class name generation being different in dev to prod and potential clashes but I can't figure out how to fix it.
I have a js file which looks like:
import { makeStyles } from '#material-ui/core/styles';
const useStyles = makeStyles({
someClass: {
backgroundColor: 'red',
},
});
export default useStyles;
I then have multiple tsx files which use this, something like:
const Example = (props: IExampleState) => {
const styles = useStyles();
return (
<SomeMUIElement className={styles.someClass}>
{some inner stuff}
</SomeMUIElement>
)
}
const mapStateToProps = (state: IExampleState) => {
...
}
export default connect(mapStateToProps)(Calls);
In production none of these styling appear, and in dev tools I can see that there are no class names applied either, also appear to be no errors.
I'm sure I am missing something!

Avoid double components with single element components

I'm often creating components styled with styled-component that only consist of a single element, e.g:
const StyledButton = styled.button({
color: '#fff',
borderRadius: '2px'
})
const Button = ({ children, ...rest }) => (
<StyledButton {...rest}>{children}</StyledButton>
)
export default Button
It feels redundant to have nested components. Is there a more terse way to accomplish the above?
I've tried to do a export default, but then the React dev tools doesn't recognize the component and displays it as "Unknown".
To my understanding, it isn't possible to pass children to a styled-component?
If you just wanted to render children and pass on props, there is no need to create the extra Button component. Instead you can just export StyledButton and use it as in:
<StyledButton onClick={buttonProp}>Children you want</StyledButton>
With this approach, you might miss out on the names for components, they show up as styled.button in devtools. To overcome this, there are two methods depending on the version.
Use the babel plugin for styled components.
You can install it with
npm install --save-dev babel-plugin-styled-components
and use it by adding it to babel plugins:
{
"plugins": ["babel-plugin-styled-components"]
}
If you 4.0 or above, you can make use of the babel macro
Just change your imports to:
import styled from 'styled-components/macro';
const StyledButton = styled.button`
color: red;
`
You do not need to nest the element, you can export it directly.
<SomeComp {...rest}>{children}</SomeComp>
is equivalent to
<SomeComp {...props} />
so you do not need to separate the children and nest them.

Resources