Reputation: 39
I'm trying to make a list where, when you click on the title, it shows/hide the description below each one. It is partly working (when you click on a title, it shows all the descriptions and when you click again, it hides them all), but I need it to show/hide each item individualy.
import React from 'react'
import styled from 'styled-components'
import girl from '../assets/steps-image.png'
import arrow from '../assets/down-arrow.svg'
class StepsSection extends React.Component{
constructor() {
super();
this.state = {
show: true
}
}
render() {
return (
<StepsStyles className="sections">
<Illustration />
<Content>
<div><span className="tag">3 easy steps</span></div>
<h1>How it works</h1>
Here we have the list:
<ul>
{Steps.map((lista, i)=>(
<li key={i}>
<div key={i} onClick={()=>{this.setState({show:!this.state.show})}} className="dropdown"><h2>{lista.title}</h2><img src={arrow} alt="" /></div>
{ this.state.show? <p>{lista.desc}</p> : null}
</li>
))}
</ul>
</Content>
</StepsStyles>
)
}
}
export default StepsSection
This is just styled components:
const StepsStyles = styled.div`
background: url(${girl}) no-repeat left;
background-position: left center;
background-size: contain;
margin-top: 200px;
text-align: left;
display: grid;
height: 50vh;
grid-template-columns:1fr 1fr;
/* max-height: 50vh; */
h1{
font-weight: bold;
margin-bottom: 5vh;
}
`
const Illustration = styled.div`
grid: 1;
`
const Content = styled.div`
grid: 2;
text-align: left;
img {
max-width: 10px;
max-height: 10px;
}
h2{
font-weight: bold;
font-size: 16px;
}
ul{
width: 60%;
}
li {
margin-bottom: 2vh;
padding-bottom: 20px;
border-bottom: 1px solid var(--superlight-gray);
::last-child{
border-bottom: none;
}
.dropdown {
display: flex;
justify-content: space-between;
align-items: center;
gap: 10px;
}
}
`
And the json static data lays here on the bottom:
const Steps = [
{
title: '1. Download Tattoo master app (dropdown)',
desc: 'Download the application in App Store and you acan find the wizard in any location around the world. '
},
{
title: '2. Enter your location',
desc: 'Download the application in App Store and you acan find the wizard in any location around the world.'
},
{
title: '3. Find your tattoo master',
desc: 'Download the application in App Store and you acan find the wizard in any location around the world.'
}
]
here is the page: https://mastertattoo-landpage.netlify.app and repo:https://github.com/micazev/mastertattoo-landpage
Any ideas? Thanks in advance!
Upvotes: 1
Views: 1720
Reputation: 766
You need to create a state for each one of your list elements. Then you can change them individually.
First I'd add an id
to each one of the Steps
item.
const Steps = [
{
id: 1,
title: '1. Download Tattoo master app (dropdown)',
desc: 'Download the application in App Store and you acan find the wizard in any location around the world. '
},
{
id: 2,
title: '2. Enter your location',
desc: 'Download the application in App Store and you acan find the wizard in any location around the world.'
},
{
id: 3,
title: '3. Find your tattoo master',
desc: 'Download the application in App Store and you acan find the wizard in any location around the world.'
}
]
Second I'd change my show
state to an Object. That way I can store the id of each item and them tell if it is true
or false
.
this.state = {
show: {}
}
And finally I'd change the function to change each item state based on its id
.
toggleListItem(itemId) {
this.setState((prevState) => ({
...prevState,
show: {
...prevState.show,
[itemId]: !prevState.show[itemId]
}
}))
}
<div key={lista.id} onClick={() => this.toggleListItem(lista.id)} className="dropdown"> ... </div>
You can see it working here: https://codesandbox.io/s/priceless-browser-uxdr5
You can have a quick explanation about using prevState
here:
What is prevState in ReactJS?
Upvotes: 0
Reputation: 26
You can use something like this...
{Steps.map((lista, index) => (
<details className='collapse'>
<summary className='title'>{lista.title}</summary>
<div className='description'>
{lista.desc}
</div>
</details>
))}
details and summary are HTML tags for collapse.
Upvotes: 1
Reputation: 158
if you are trying to change the state by the value in the state please pass a function to setState as first argument like this:
this.setState((state, props) => ({
show: !state.show
}));
Upvotes: 0