Состояние для каждого элемента в компоненте
У меня есть компонент который рендерит список элементов с подэлементами. Отдельный элемент вынесен во внешний компонент, чтобы каждый элемент имел свое состояние, но почему то по нажатию на один элемент, состояние меняется у всех элементов(раскрываются все элементы). Только начинаю погружаться в реакт, подскажите пожалуйста в чем моя ошибка?
Первый компонент с выводом списка
import React, {useState, useEffect} from 'react';
import axios from 'axios';
import classes from './Catalog.module.css';
import CustomInput from '../CustomInput/CustomInput'
import Item from './Item/Item'
const Catalog = (props) => {
const [somethingData, setSomethingData] = useState([]);
const [inputValue, setValue] = useState('');
const getData = () => {
axios.get('http://localhost:3001/somethingData')
.then(response => setSomethingData(response.data))
.catch(error => console.log(error))
}
useEffect(() => {
getData()
}, []);
const filterData = somethingData.filter(item => {
return item.title.toLowerCase().includes(inputValue.toLocaleLowerCase())
})
const renderItem = (items) => {
return <Item key={items.id} filterData={filterData} />
}
return (
<div className={classes.catalog}>
<CustomInput setValue={setValue}/>
{renderItem(somethingData)}
</div>
)
}
export default Catalog;
Второй компонент с рендером элемента
import classes from './Item.module.css';
import { useState } from 'react';
const Item = (props) => {
const [visible, setVisible] = useState(false);
const handleClick = () => {
setVisible(!visible)
}
let elementData = props.filterData.map(el =>
<div key={el.id}>
<div className={classes.title} onClick={handleClick}>
{el.title}
<div className={classes.line}></div>
<div className={classes.showed}> {visible ? 'скрыть' : 'показать'} </div>
</div>
{visible ? el.dataSection.map(e =>
<div className={classes.content} key={e.key}>
<a href={e.url} target='blanck'> { e.section } </a>
</div>) : null}
</div>
)
return (
<div>
{elementData}
</div>
)
}
export default Item;
Мой json файл
"somethingData": [
{
"id": "1",
"title": "Первый элемент",
"dataSection": [
{
"key": "1",
"section": "Подэлемент",
"url": "http://google.com"
}
]
},
{
"id": "2",
"title": "Второй элемент",
"dataSection": [
{
"key": "1",
"section": "Первый подэлемент",
"url": "http://yandex.ru"
},
{
"key": "2",
"section": "Второй подэлемент",
"url": "https://ru.reactjs.org/"
}
]
}
]
}
Ответы (1 шт):
Автор решения: Konstantin Modin
→ Ссылка
В функцию renderItem я добавил map функцию по данным, которая отображает каждый Item. Вот рабочий вариант как можно сделать:
import React, { useState, useEffect } from "react";
// import CustomInput from "../CustomInput/CustomInput";
const Catalog = (props) => {
const [somethingData, setSomethingData] = useState([]);
const [inputValue, setValue] = useState("");
const getData = () => {
setSomethingData(data);
};
useEffect(() => {
getData();
}, []);
const filterData = somethingData.filter((item) => {
return item.title.toLowerCase().includes(inputValue.toLocaleLowerCase());
});
const renderItem = () => {
return filterData.map(({ id, title, dataSection }) => {
return <Item key={id} title={title} dataSection={dataSection} />;
});
};
return (
<div>
{/* <CustomInput setValue={setValue} /> */}
{renderItem()}
</div>
);
};
export default Catalog;
const Item = ({ title, dataSection }) => {
const [visible, setVisible] = useState(false);
const handleClick = () => {
setVisible(!visible);
};
return (
<div>
Title: {title}
<button onClick={handleClick}> {visible ? "скрыть" : "показать"} </button>
{visible
? dataSection.map(({ key, section, url }) => (
<div key={key}>
<a href={url} target="blank">
{section}
</a>
</div>
))
: null}
</div>
);
};
const data = [
{
id: "1",
title: "Первый элемент",
dataSection: [
{
key: "1",
section: "Подэлемент",
url: "http://google.com",
},
],
},
{
id: "2",
title: "Второй элемент",
dataSection: [
{
key: "1",
section: "Первый подэлемент",
url: "http://yandex.ru",
},
{
key: "2",
section: "Второй подэлемент",
url: "https://ru.reactjs.org/",
},
],
},
];