Styled-component not taking props - reactjs

I'm trying to pass props to my styled component. I am using the styled-component npm dependency.
import React, { Component } from 'react';
import styled from 'styled-components';
class WidgetContainer extends Component {
render() {
return (
<Wrapper name='widget-container'>
</Wrapper>
);
}
}
const mapStateToProps = state => {
return {
user: state.user,
bannerStatus: true
};
};
export default withRouter(connect(mapStateToProps)(WidgetContainer));
const Wrapper = styled.div`
display: flex;
flex-direction: column;
width: 100%;
min-height: 100vh;
margin: auto;
align-items: center;
justify-content: flex-start;
background: -webkit-linear-gradient(top, rgba(162, 209, 234, 1) 0%, rgba(56, 83, 132, 1) 100%);
padding-top: ${(props) => {
console.log(props.bannerStatus)
console.log('DATA')
return props.user ? '160px' : '126px'}};
overflow-y: auto;
padding-bottom: 40px;
#media(max-width: 768px) {
padding-top: 126px;
padding-bottom: 5px;
}
`;
The console.log you can see returns undefined. Even though the value is hard-coded. The ternary operator doesn't work as a result.
Here are the docs: https://www.styled-components.com/docs/basics#adapting-based-on-props.

You are mapping state to props in only the WidgetContainer. Your Wrapper component is not being passed any props.
Try
<Wrapper bannerStatus={props.bannerStatus} name='widget-container' />
OR
<Wrapper user={props.user} bannerStatus={props.bannerStatus} name='widget-container' />

Related

React. Two buttons in a component but only one button works

I am practicing React basics.
I have a component mapped from an array of objects and it shows twice in my website but only on the second time the button works. the first button does not seem to be recognised.
Can someone explain why please? I can't find a reason for this but I am sure it is something obvious I am missing
A link to sandbox
App.js
import MainComponent from "./components/MainComponent";
function App() {
return (
<div>
<MainComponent />
</div>
);
}
export default App;
MainComponent.js
import React from "react";
import TextItem from "./TextItem";
const text = [
{
image:
"https://pbs.twimg.com/profile_images/626298192418607105/4KBKHQWi_400x400.jpg",
title: "This is a whale",
subtitle: "It is a large mammal",
price: "£ 167.87 + VAT",
uom: "per Unit",
},
{
image:
"https://news.artnet.com/app/news-upload/2019/01/Cat-Photog-Feat-256x256.jpg",
title: "This is a cat",
subtitle: "It is a small mammal",
price: "£ 17.87 + VAT",
uom: "per Unit",
},
];
const MainComponent = () => {
return (
<div>
{text.map((eachText, i) => (
<TextItem
key={i}
image={eachText.image}
title={eachText.title}
subtitle={eachText.subtitle}
price={eachText.price}
uom={eachText.uom}
/>
))}
</div>
);
};
export default MainComponent;
TextItem.js
import React from "react";
import styled from "styled-components";
import Card from "../UI/Card";
const TextItem = (props) => {
const onClickHandler = () => {
console.log("clicked");
};
return (
<Card>
<DivFlex>
<ImgDiv>
<img src={props.image} alt={"a whale"} />
</ImgDiv>
<TitleDiv>
<h1>{props.title}</h1>
<h3>{props.subtitle}</h3>
</TitleDiv>
<PriceDiv>
<h2>{props.price}</h2>
<h2>{props.uom}</h2>
</PriceDiv>
<EditDiv>
<Button onClick={onClickHandler}>Edit this</Button>
</EditDiv>
</DivFlex>
</Card>
);
};
const DivFlex = styled.div`
display: flex;
justify-content: center;
align-items: center;
width: 800px;
height: 600px;
`;
const ImgDiv = styled.div`
width: 90px;
height: 90px;
margin-right: 3%;
img {
max-width: 100%;
height: 100%;
border-radius: 6px;
}
`;
const TitleDiv = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
width: 30%;
margin-right: 3%;
`;
const PriceDiv = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-end;
width: 20%;
margin-right: 3%;
`;
const EditDiv = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
width: auto;
margin-left: 3%;
`;
const Button = styled.div`
outline: none;
border: none;
background: maroon;
color: white;
padding: 1.2rem 1.8rem;
font-size: 22px;
border-radius: 8px;
cursor: pointer;
`;
export default TextItem;
This is happening due to the conflicting heights of Card and DivFlex. The Card has an height of 140px but its child DivFlex has a height of 600px. So, the next item is basically overlapping the previous item and hence you are not able to click the first button. You can observe the same behaviour if you had any number of items. Only the last item would be clickable due to it overlapping on top of previous item.
One way to fix this is to remove the height from Card component and change the height of DivFlex to 140px instead.
PS: It didn't happen in the replica sandbox because you didn't use the Card component there and used a regular div which by default has a height of auto

onClick not working on Draggable icon in react js?

I have a draggable icon. But onClick is not working on that icon.
import styled from "#emotion/styled"
import Draggable from 'react-draggable';
import { BsPlusCircle } from 'react-icons/bs';
const StartWrapper = styled.div`
position: absolute;
bottom: 74px;
display: block;
margin: 0 auto;
width: calc(100% - 24px);
font-family: Montserrat, sans-serif;
font-size: 14px;
font-style: normal;
font-weight: 500;
letter-spacing: 0em;
text-align: center;
color: rgba(91, 91, 91, 0.69);
border: 1px solid white;
height: 170px;
line-height: 170px;
`
export const App = ( ) => {
const show = () => {
console.log("Show");
}
return (
<StartWrapper onClick={()=> start()}>
<Draggable>
<BsPlusCircle onClick={() => show()} />
</Draggable>
</StartWrapper>
)
}
The start function works. But the show function does not work. Any help will be greatly appreciated.
Looks like you need to pass a ref to the StartWrapper and Draggable components
import styled from "#emotion/styled";
import { useRef } from "react";
import Draggable from "react-draggable";
import { BsPlusCircle } from "react-icons/bs";
const StartWrapper = styled.div`
position: absolute;
bottom: 74px;
display: block;
margin: 0 auto;
width: calc(100% - 24px);
font-family: Montserrat, sans-serif;
font-size: 14px;
font-style: normal;
font-weight: 500;
letter-spacing: 0em;
text-align: center;
color: rgba(91, 91, 91, 0.69);
border: 1px solid white;
height: 170px;
line-height: 170px;
`;
export const App = () => {
const ref = useRef(null); //ADD THIS
const show = () => {
console.log("Show");
};
return (
//Then pass refs to StartWrapper and Draggable
<StartWrapper ref={ref} onClick={() => console.log("Hello")}>
<Draggable ref={ref}>
<BsPlusCircle onClick={() => show()} />
</Draggable>
</StartWrapper>
);
};
This works for me in codesanbox
findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of DraggableCore which is inside StrictMode

Passing custom props to styled-component in typescript [duplicate]

This question already has answers here:
Using styled-components with props and TypeScript
(8 answers)
Closed 1 year ago.
I'm new to React with Typescript and Styled-Component and I came across this issue. I created a 'Header' component and I was trying to pass the state whenever the button is clicked into the HeaderStyled as a probs to change the CSS style depends on the state but I got error.
import React, {useState} from 'react'
import HeaderStyled from './Header_styled';
const Header = () => {
const [open,setOpen] = useState(false);
return (
<HeaderStyled open={open}>
<img src="/images/logo.svg" alt="sunnyside_logo" />
<ul>
<li>About</li>
<li>Services</li>
<li>Projects</li>
<li><button>CONTACT</button> </li>
</ul>
<div onClick={() => setOpen(!open)}>
<div></div>
<div></div>
<div></div>
</div>
</HeaderStyled>
)
}
export default Header;
Here is my HeaderStyled component
const HeaderStyled = styled.div `
background-color: ${theme.primaryBlue};
display: flex;
justify-content: flex-end;
padding: 20px 20px;
align-items: center;
ul {
position: absolute;
background-color: white;
top: 6%;
width: 80%;
height: 25%;
right: 10%;
display: flex;
flex-direction: column;
padding: 0px;
align-items: center;
justify-content: space-around;
transform: ${({open}) => open ? 'translateX(0)': 'translateX(120%)'};
li {
padding: 0px;
a {
color: #0000002e;
}
}
button {
background-color: yellow;
color: black;
}
}
The error I got from HeaderStyled
Have a look in the Styled Components docs for Typescript - Using custom props
import React, { useState } from "react";
import styled from "styled-components";
interface Props {
open: boolean;
}
const HeaderStyled = styled.div<Props>``;
const Header = () => {
const [open, setOpen] = useState(false);
return <HeaderStyled open={open}></HeaderStyled>;
};
export default Header;
The way to do it in TS is to define a type or an interface and add that to the styled component:
type HeaderStyledProps = {
open: boolean;
}
const HeaderStyled = styled.div<HeaderStyledProps>`
background-color: ${theme.primaryBlue};
display: flex;
justify-content: flex-end;
padding: 20px 20px;
align-items: center;
ul {
position: absolute;
background-color: white;
top: 6%;
width: 80%;
height: 25%;
right: 10%;
display: flex;
flex-direction: column;
padding: 0px;
align-items: center;
justify-content: space-around;
transform: ${({open}) => open ? 'translateX(0)': 'translateX(120%)'};
li {
padding: 0px;
a {
color: #0000002e;
}
}
button {
background-color: yellow;
color: black;
}
}
`

How to EXTEND imported component styled components

I cannot extend my imported component. I was looking into styled components docs and find that in v4+ should works prop "as", but it doesnt.
COMPONENT:
type Props = {
padding: string,
justify: string
}
const FlexContainer = styled.div<Props>`
padding: ${props => props.padding};
display: flex;
flex-wrap: wrap;
justify-content: ${props => props.justify};
`
export const Flexcontainer: React.FC<Props> = props =>{
return (
<FlexContainer padding={props.padding} justify={props.justify}>
{props.children}
</FlexContainer>
)
}
EXTENDED STYLE:
import { Flexcontainer } from '../../reusable/FlexContainer';
const FlexContainerExtended = styled.div`
color: red;
`
USE:
<FlexContainerExtended
padding={null}
justify={"flex-start"}
as={Flexcontainer}>
You just have to add a prop className to your Flexcontainer component like this:
export const Flexcontainer: React.FC<Props> = props =>{
return (
<FlexContainer className={props.className} padding={props.padding} justify={props.justify} >
{props.children}
</FlexContainer>
)}
To override styles, styled-components passes a className as props to the overrided component, it's why
You can just pass the base component to the styled function to override it.
type Props = {
padding: string,
justify: string
}
const FlexContainer = styled.div<Props>`
padding: ${props => props.padding};
display: flex;
flex-wrap: wrap;
justify-content: ${props => props.justify};
`
const FlexContainerExtended = styled(FlexContainer)`
color: red;
`
export const Flexcontainer: React.FC<Props> = props =>{
return (
<FlexContainer padding={props.padding} justify={props.justify}>
{props.children}
</FlexContainer>
)
}
// And use it like this
<FlexContainerExtended
padding={null}
justify={"flex-start"}/>
I know this question was asked a long time ago, but I leave here the solution I found for future visitors.
Base component definition
import React from 'react'
import styled from 'styled-components'
const ContainerWrapper = styled.div`
width: 100%;
max-width: 1200px;
padding-left: 5%;
padding-right: 5%;
margin-left: auto;
margin-right: auto;
`
export default function Container({ children, ...props }) {
return (
<ContainerWrapper {...props}>
{children}
</ContainerWrapper>
)
}
Extended component definition
Obs.: note that the extended component is an article, while the base component is a div, and so far they have no relationship.
Also note that the base component (Container) has been imported but not yet used.
import React from 'react'
import styled from 'styled-components'
import Container from '../../common/Container'
const HeroWrapper = styled.article`
height: 100vh;
padding-top: 74px;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
background-attachment: fixed;
`
Invoking componentes
Now, in the same file where I declared the extended component, I just call the base component, informing the name of the extended component in the as attribute.
export default function PostsWrapper() {
return (
<Container as={HeroWrapper}>
{/* ... */}
</Container>
)
}

React Styled Components Extend

i'm trying to re-use and extend a styled-component with no luck. I suspect i haven't quite grasped how to properly use styled-components
I have a component that renders a chevron icon, based on what icon prop is passed to it. What i want to be able to do is export this component, then import it and extend its styles. ie - in this example remove its padding in Header.jsx:
Chevron.jsx
import React from 'react'
import styled from 'styled-components'
const StyledChevron = styled.i`
display: flex;
align-items: center;
justify-content: center;
padding: 14px;
cursor: pointer;
border-left: 1px solid #efefef;
transition: all .1s linear;
transform: rotate(0deg);
${props=>props.closed && ``};
&:hover {
background: #f7f4f4;
}
`
const Chevron = (props) => {
return (
<StyledChevron closed={props.item.closed} onClick={()=>{props.openSubMenu(props.item.id)}} className={props.icon}/>
)
}
export default Chevron
Header.jsx
import React from 'react'
import styled from 'styled-components'
import cssvars from '../../js/style/vars'
import Chevron from './Chevron'
const StyledHeader = styled.div`
display: flex;
align-items: center;
padding: 11px;
justify-content: space-between;
background: ${cssvars.primaryColor};
h2 {
font-size: 19px;
color: #fff;
display: flex;
align-items: center;
}
`
const BackChevron = Chevron.extend`
padding: 0
`
const Header = (props) => {
return (
<StyledHeader>
<h2>{props.item.title}</h2>
<BackChevron {...props} icon="icon-arrow-left"/>
</StyledHeader>
)
}
export default Header
With the above code, im getting console error: Uncaught TypeError: _Chevron2.default.extend is not a function
styled-components has some kind of inheritance
Chevron.jsx
import React from 'react'
import styled from 'styled-components'
const StyledChevron = styled.i`
display: flex;
align-items: center;
justify-content: center;
padding: 14px;
cursor: pointer;
border-left: 1px solid #efefef;
transition: all .1s linear;
transform: rotate(0deg);
${props => props.closed && ``};
&:hover {
background: #f7f4f4;
}
`
const Chevron = (props) => (
<StyledChevron
closed={props.item.closed}
onClick={() => props.openSubMenu(props.item.id)}
className={props.icon}
/>
)
export default Chevron
Header.jsx
import React from 'react'
import styled from 'styled-components'
import cssvars from '../../js/style/vars'
import Chevron from './Chevron'
const StyledHeader = styled.div`
display: flex;
align-items: center;
padding: 11px;
justify-content: space-between;
background: ${cssvars.primaryColor};
h2 {
font-size: 19px;
color: #fff;
display: flex;
align-items: center;
}
`
const BackChevron = styled(Chevron)`
padding: 0
`
const Header = (props) => (
<StyledHeader>
<h2>{props.item.title}</h2>
<BackChevron {...props} icon="icon-arrow-left"/>
</StyledHeader>
)
export default Header
as said in #yury-tarabanko comment

Resources