Хорошо, давайте возьмем это сверху.Я полагаю, у вас есть данные, которые вы хотите отобразить как <Card />
, по одному для каждого элемента данных.Вы не держите компоненты в состоянии, а, скорее, данные.Например:
this.state = {
data: [
{value: 'Cat 1'},
{value: 'Cat 2'},
{value: 'Cat 3'}
]
}
В этом случае родитель должен хранить данные правильно.Тем не менее, вся концепция подъема состояния (ссылка React docs) не так уж сложна.В основном, это вопрос: заботится ли более чем один компонент / зависит от одного и того же состояния? Если ответ положительный, обычно родитель должен его содержать.Вы правы в том, что каждая карта имеет свое собственное активное состояние.Тем не менее, родитель мог сделать это также.Тогда давайте сделаем это:
Board.js
import React from 'react';
import {Card} from './Card';
class Board extends React.Component{
state = {
data: [
{value: 'Cat 1'},
{value: 'Cat 2'},
{value: 'Cat 3'}
],
activeCard: null,
}
cardClick = id => {
this.setState({ activeCard: id })
}
addCard = () => {
const newCard = { value: 'Some val here' };
this.setState({ data: [...this.state.data, newCard] });
}
render(){
return(
<div id="Board">
<button onClick={this.addCard}>Add a card</button>
{this.state.data.map((item, index) =>
<Card key={index}
value={item.value}
active={this.state.activeCard === index}
cardClick={this.cardClick}
index={index}
/>
)}
</div>
)
}
}
export default Board;
Делая это, наш родитель управляет всем.Не сказать, что это единственный правильный путь, но это позволяет нам иметь компонент Card
в качестве «тупого», функционального компонента.Будьте осторожны - этот конкретный подход основан на том, что данные никогда не меняются в порядке, поскольку он опирается на индекс .map
, который составляет от 0 до длины данных - 1.
Card.js
import React from 'react';
const Card = props => (
<div
className={props.active ? 'activeCard' : 'inactiveCard'}
onClick={() => props.cardClick(props.index)}
>
Active
</div>
);
export { Card };
Есть несколько ключевых различий между тем, что вы опубликовали, и тем, что я сделал.
1) Вы отображали карты с одинаковым id="card"
, что плохо, идентификатор должен бытьуникальный.Кроме того, если вам это действительно не нужно, вы можете его опустить.
2) Я переключаю className
на основе индекса активной карты.Если текущая карта, скажем, 2, также является активной картой, она будет иметь activeCard
className.
3) Наконец, я передаю функцию ребенку, которая обновляет состояние родителей.Таким образом, у меня есть состояние, содержащееся в родительском элементе, и каждый раз, когда я обновляю его, оно будет отражаться и на дочерних элементах.Это не значит, что ваш подход к использованию компонентов на основе классов для карт является неправильным, но я думаю, что это проще.
4) Просто выбросить его туда, WAI-ARIA недействительно согласен с div, имеющим onClick
событий.Чтобы сделать Интернет классным, доступным местом, вы можете поставить role="button"
на div, чтобы обозначить, что это кнопка.Это также требует, чтобы он был фокусируемым, а также слушателем событий клавиатуры, и в этом случае вам, вероятно, лучше просто использовать <button>
, если элемент должен быть кликабельным.
Чтобы ответить на другие ваши вопросы:
Родитель автоматически передает все изменения состояния всем дочерним элементам, которые заботятся о нем
Все дочерние компоненты независимы от родителя, например, если ониесть свои состояния, родителю все равно.Это становится актуальным только тогда, когда они совместно используют функцию состояния и обновления состояния, поэтому только если вы специально передаете такую функцию дочерним элементам
Если дочерние элементы совместно используют состояние, тогдаБыть поднятым, что объясняется в документе, связанном!
РЕДАКТИРОВАТЬ : для данного примера я предположил, что вы хотите только одну активную карту за раз.Если это не так, либо пусть каждая карта удерживает свои активные состояния, как предложил Кено Клейтон, либо измените activeCard
на массив, сверяя индекс каждой карты с массивом активных карт