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

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

Related

Set Background Image using props in Styled Components

This is the Home Component. I am passing the Details as props to Main component
import React from 'react'
import Main from '../components/Main'
import Navbar from '../components/Navbar'
const Home = () => {
return (
<div>
<Navbar/>
<Main
title = "Model Y"
text = "Schedule a Demo Drive"
bgImg = "../assets/model-x.jpg"
leftBtnText = "Custom Order"
rightBtnText = "View Inventory"
/>
</div>
)
}
export default Home
This is the main components
import React from 'react';
import styled from 'styled-components';
import KeyboardArrowDownOutlinedIcon from '#mui/icons-material/KeyboardArrowDownOutlined';
const Container = styled.div`
height: 100vh;
width: 100%;
/* background-image: url('../assets/model-y.jpg'); */
background-image: ${props => `url(${props.bgImage})`};
background-size: cover;
background-position: center;
background-repeat: no-repeat;
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
gap:15rem;
`;
const Heading = styled.div`
flex:3;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
`;
const Title = styled.h1`
font-size: 2.7rem;
font-weight: 700;
color:#202328;
`;
const Text = styled.p`
font-weight:500;
font-size: 1rem;
letter-spacing: 0.4px;
cursor: pointer;
color:#202328;
`;
const Line = styled.span`
height: 1.1px;
background-color: black;
width: 100%;
`;
const Buttons = styled.div`
display: flex;
align-items: center;
gap: 2rem;
`;
const Bottom = styled.div`
flex:1;
display:flex;
flex-direction: column;
align-items: center;
gap:2rem;
`;
const ButtonLeft = styled.button`
padding: 0.6rem 6rem;
border-radius: 0.5rem;
border: none;
font-size: 1rem;
font-weight: 900;
background-color: rgba(23,26,32,0.8);
color: white;
opacity:0.80;
cursor: pointer;
`;
const ButtonRight = styled(ButtonLeft)`
background-color: white;
color: #202328;
opacity:0.70;
`;
const DownArrow = styled.div`
animation:bounce infinite 1s;
color:white;
cursor:pointer;
`;
const Main = (props) => {
return (
<Container bgImage={props.bgImg}>
<Heading>
<Title>{props.title}</Title>
<Text>
{props.text}
</Text>
<Line/>
</Heading>
<Bottom>
<Buttons>
<ButtonLeft>{props.leftBtnText}</ButtonLeft>
<ButtonRight>{props.rightBtnText}</ButtonRight>
</Buttons>
<DownArrow>
<KeyboardArrowDownOutlinedIcon fontSize='large'/>
</DownArrow>
</Bottom>
</Container>
)
}
export default Main
The file structure (for Images path)
enter image description here
I want the background Image I am passing as props to be visible.
After using the above code it looks like this
enter image description here
As you can see the Image is not visible behind but in inspect you can clearly see the correct url for image is there.
Please Help.
You should import the background image.
import bg from '../assets/model-x.jpg';
and pass the imported bg to the bgImg props.
like this:
import React from 'react'
import Main from '../components/Main'
import Navbar from '../components/Navbar'
import bg from '../assets/model-x.jpg';
const Home = () => {
return (
<div>
<Navbar/>
<Main
title="Model Y"
text="Schedule a Demo Drive"
bgImg={bg}
leftBtnText = "Custom Order"
rightBtnText = "View Inventory"
/>
</div>
)
}
export default Home

Flexbox Container with Child in it with position absolute

I'm new to React, and I'm currently building a slideshow on my website. Basically, I have a left arrow, the slide content, then the right arrow in my flexbox for my slideshow. However, to make my arrows on the edges of the screen I needed to use position absolute, which messes up my flexbox container. I figured out that absolutely positioned child items don't count in the flexbox of the parent, but is there a way around that? As of now, my image is overlapping with the left arrow. Thanks, and sorry if this is poorly written since I'm very new to this all. Code will be below.
Image: [1]: https://i.stack.imgur.com/PkL3Z.jpg
import { ArrowBackIosOutlined, ArrowForwardIosOutlined } from '#material-ui/icons'
import React from 'react'
import styled from 'styled-components'
import grocery from '../assets/grocery.png'
const Container = styled.div`
width: 100%;
height: 100vh;
display: flex;
position: relative;
`
const Arrow = styled.div`
width: 50px;
height: 50px;
background-color: #fff7f7;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
position: absolute;
top: 0;
bottom: 0;
left: ${props => props.direction === "left" && "10px"};
right: ${props => props.direction === "right" && "10px"};
margin: auto;
cursor: pointer;
opacity: 0.5;
`
const Wrapper = styled.div`
height: 100%;
`
const Slide = styled.div`
width; 100vw;
height: 100vh;
display: flex;
align-items: center;
`
const ImageContainer = styled.div`
height: 100%;
flex: 1;
margin-top: 50px;
`
const Image = styled.img`
height: 50%;
`
const InfoContainer = styled.div`
flex: 1;
`
const Slider = () => {
return (
<Container>
<Arrow direction="left">
<ArrowBackIosOutlined/>
</Arrow>
<Wrapper>
<Slide>
<ImageContainer>
<Image src={https://images.unsplash.com/photo-1481349518771-20055b2a7b24?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxzZWFyY2h8M3x8cmFuZG9tfGVufDB8fDB8fA%3D%3D&w=1000&q=80}/>
</ImageContainer>
</Slide>
</Wrapper>
<Arrow direction="right">
<ArrowForwardIosOutlined/>
</Arrow>
</Container>
)
}
export default Slider

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 center buttons with styled-components?

Can't figure out how to center 2 buttons horizontally with styled-components.
Below is my code.
Tried many ways to center, but didn't work.
import React from "react"
import styled from "styled-components"
const HomeStyles = styled.div`
h1 {
font-size: 1.5em;
text-align: center;
color: royalblue;
}
button {
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid royalblue;
border-radius: 3px;
color: royalblue;
}
`
export default function Home() {
return (
<HomeStyles>
<h1>Title</h1>
<button>Button1</button>
<button>Button2</button>
</HomeStyles>
)
}
UPDATE: I need to center buttons horizontally
Have you tried using flexbox on parent element?
const HomeStyles = styled.div`
display: flex;
flex-direction: column;
justify-items: center;
align-items: center;
....
`;
const ButtonsWrapper = styled.div`
display: flex;
justify-items: center;
align-items: center;
`;
<HomeStyles>
<h1>Title</h1>
<ButtonsWrapper>
<button>Button1</button>
<button>Button2</button>
</ButtonsWrapper>
</HomeStyles>

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