How to use styled-components that extends from an already styled component? - javascript

I'm trying to extract all my component styling using styled-component to a single file.
However, I am running into an error where if I extract the styling and the component which the styling is reliant into a separate file, the themes stop working.
Button.jsx
import {ButtonWrapper} from './Button.styled';
import {Button as MUButton} from '#material-ui/core/Button';
export const Button = () => {
return <ButtonWrapper>
<Button/>
</ButtonWrapper>
}
SmallButton.jsx
import {StyledSmallButton} from './Button.styled';
// import {Button} from './Button'
// const StyledSmallButton = styled(Button)` // This works.
// width: 50%
// `
export const SmallButton = () => {
return <StyledSmallButton/>
}
Button.styled.jsx
import {Button} from './Button';
export const ButtonWrapper = styled.div`
width: 100%
`;
export const StyledSmallButton = styled(Button)` //Doesn't work.
width: 50%
`;
Error
Uncaught Error: Cannot create styled-component for component: undefined
I believe there is a cyclic dependency problem here i.e. SmallButton requires Button which is themed by ButtonWrapper.
How can I solve this?

I think you've imported the MUButton wrong. Should the <Button /> component actually be <MUButton />?
import {ButtonWrapper} from './Button.styled';
import {Button as MUButton} from '#material-ui/core/Button';
// ^ this is the alias
export const Button = ({ className }) => {
return <ButtonWrapper>
<MUButton className={className} />
// ^ This should be MUButton
</ButtonWrapper>
}
Edit: passed the className prop down as mentioned by Andy int he comments

Related

Why is the keyword 'default' necessary when exporting a component withStyles

When I implement a simple React component with Mui's withStyles HOC, I have to use the keyword "default" when exporting the component. Why can't I use the HOC in the return statement within the functional component?
Is there something about Js or ReactJs that I'm missing?
Since I am forced to export this component as default, I lose the possibility to use the named import functionality, without using another import/export layer in between.
Below is the current working code:
// Card.js
import React from "react";
import {
Card,
withStyles
} from "#material-ui/core";
const styles = theme => ({
card: {
margin: theme.spacing(2)
}
});
function CustomCard(props) {
const {classes} = props;
return (
<Card className={classes.card}>
Export me without being the default component.
</Card>
);
}
export default withStyles(styles)(MediaCard);
// Elsewhere.js
import CustomCard from "Card";
...
But i'd rather write something like this:
// Cards.js
import React from "react";
import {
Card,
withStyles
} from "#material-ui/core";
const styles = theme =\> ({
card: {
margin: theme.spacing(2)
},
anotherCard: {
margin: theme.spacing(4)
}
});
export function CustomCard(props) {
const {classes} = props;
return withStyles(styles)(
<Card className={classes.card}>
Jeah. I'm not the default component.
</Card>
);
}
export function AnotherCard(props) {
const {classes} = props;
return withStyles(styles)(
<Card className={classes.anotherCard}>
Jeah. I'm not the default component either.
</Card>
);
}
// Elsewhere.js
import { CustomCard, AnotherCard } from "Cards";
...
You can do it the way you want to but you to change the way you define your components. The technical reason is that all exports except default need to be named, otherwise you can't import them and know what's what. Since withStyles() returns a statement and not a named variable/function you can't export it without a name.
export const AnotherCard = withStyles(styles)((props) => {
const {classes} = props;
return (
<Card className={classes.anotherCard}>
Jeah. I'm not the default component either.
</Card>
);
});
The downside of this is of course now your components aren't hoisted.

Getting SyntaxError when using lightweight-charts in NextJS

I'm trying to use the lightweight-charts package in my nextjs project, however when i try to call the createChart function I get this error in my nodejs console.
...\lightweight-charts\dist\lightweight-charts.esm.development.js:7
import { bindToDevicePixelRatio } from 'fancy-canvas/coordinate-space';
^^^^^^
SyntaxError: Cannot use import statement outside a module
Component:
import styled from "styled-components"
import { createChart } from 'lightweight-charts';
const Wrapper = styled.div``
const CoinPriceChart = () => {
const chart = createChart(document.body, { width: 400, height: 300 });
return <Wrapper></Wrapper>
}
export default CoinPriceChart
Page:
import styled from "styled-components"
import CoinPriceChart from "../../components/charts/CoinPriceChart"
const Wrapper = styled.div``
const CoinDetailPage = () => {
return (
<Wrapper>
<CoinPriceChart />
</Wrapper>
)
}
export default CoinDetailPage
Does someone have an idea what I could do to enable me to use the library within nextjs?
Thank you!
That because you are trying to import the library in SSR context.
Using next.js Dynamic with ssr : false should fix the issue :
import styled from "styled-components"
import dynamic from "next/dynamic";
const CoinPriceChart = dynamic(() => import("../../components/charts/CoinPriceChart"), {
ssr: false
});
const Wrapper = styled.div``
const CoinDetailPage = () => {
return (
<Wrapper>
<CoinPriceChart />
</Wrapper>
)
}
export default CoinDetailPage

NETXJS: transfer data from page to component with hooks

Hey how are you? i'm using nextjs / styled components and i would like to change a string via props. I made a layout component with a main and it has an props to make it dinamic per page
Page 'prueba.js'
import React from 'react';
import Layout from '../components/Layout/Layout';
const prueba = () => {
const setNewBackground = 'green';
console.log(setNewBackground)
return (
<Layout setNewBackground={setNewBackground}>
<p>holaaaaa</p>
</Layout>
);
}
export default prueba;
Layout.js component
import React,{useState} from 'react';
import Main from './Main';
const Layout = props => {
const [background, setBackground] = useState('blue')
const setNewBackground = () => {
setBackground (background);
}
return (
<>
<Main newBackground={background}>
{props.children}
</Main>
</>
);
}
export default Layout;
And Main.js component
import styled from '#emotion/styled';
const Main = styled.main`
background:${props => props.newBackground};
height:100vh;
width:100%;
`;
export default Main;
I check it in console but it shows me undefined. Wheres the error :(? thanks and have a good year!
You don't need to create a state for that. You can use only the color prop you passed to the Layout.
Prueba.js
import React from 'react';
import Layout from '../components/Layout/Layout';
const prueba = () => {
return (
<Layout backgroundColor='green'>
<p>holaaaaa</p>
</Layout>
);
}
export default prueba;
Layout.js
import React,{useState} from 'react';
import Main from './Main';
const Layout = ({ backgroundColor, chidlren }) => {
return (
<Main backgroundColor={backgroundColor}>
{children}
</Main>
);
}
export default Layout;
Main.js
import styled from '#emotion/styled';
const Main = styled.main`
background:${({ backgroundColor }) => backgroundColor || 'your default color'};
height:100vh;
width:100%;
`;
export default Main;

functional component declare using fat arrow becomes undefined after import in react

I declare this functional component in react but when I import this component in another component It throws an error that this component is undefined and when I change this fat arrow functional to normal ES5 function, it works! why ???
export default ActionButton = (props) => {
return (
<div>
<button>
<FontAwesomeIcon icon={faPlusSquare} className={classes.ButtonItem} />
</button>
</div>
);
}
Try defining separately with const then exporting the created ActionButton variable as:
const ActionButton = (props) => {
return (
<div>
<button>
<FontAwesomeIcon icon={faPlusSquare} className={classes.ButtonItem} />
</button>
</div>
);
}
export default ActionButton
Then you can import in the other component as - probably the path is different:
import ActionButton from './ActionButton'
You cannot export default like:
export default ActionButton = (props) => {
You should do this instead:
export default (props) => {
It's because default export has no name explicitly. That is, you can import it by any name.
However, preferred method is to define first and export later: (If you have other named exports as well)
const ActionButton = (props) => {}
export default ActionButton

Cannot read property 'styledComponentId' of undefined

I use styled-component but couldn't find a way to find match element. I got error of
TypeError: Cannot read property 'styledComponentId' of undefined
This is my index.js
const Container = styled.h1`
font-size: 14px;
import React from 'react'
import styled from 'styled-components'
const Container = styled.h1`
font-size: 14px;
`
export default () => (<div>
<Container>Hello</Container>
</div>)
export { Container }
This is my test (index.spec.js)
import React from 'react'
import { shallow } from 'enzyme'
import IndexPage from './index'
import { Container } from './index'
import { enzymeFind } from 'styled-components/test-utils'
describe('Pages', () => {
describe('Index page', () => {
it('should have a container', function() {
const wrapper = shallow(<IndexPage />)
expect(enzymeFind(wrapper, Container).exists()).toBe(true)
})
})
})
In your index.spec.js you have:
import IndexPage from './index'
import { Container } from './index'
Yet the code you posted only has a default export in index.js - you might be mixing files you are importing from.

Categories