我不确定是否最好将状态保留在单个子组件或父组件中。
我有一个父组件,它将包含一个子组件,该子组件需要能够根据需要进行复制。
我有几个问题:
我在哪里存储单个组件的状态?它是在组件本身中还是在父对象中?
如果它在子组件中,我如何告诉父组件更新其他子组件。
如果在父级中,我如何将一个函数传递给子级,以更新ITS状态而不是父级状态?
如何访问每个组件状态并告诉其根据另一个子状态的更改而更改?
目前,我正在将一个新的“卡片”组件推入一个数组,该组件跟踪我需要在“板上”渲染的所有组件。
我无法概念化管理一切状态以及如何访问每个孩子的最佳方法。他们有个人ID吗?我该如何更改其所有状态。
import React from "react";
import Card from "./Card";
export default class Board extends React.Component {
constructor(props) {
super(props);
this.state = {
cards: [<Card />]
};
}
componentDidMount() {}
createCard() {
this.state.cards.push(<Card />);
this.forceUpdate();
}
render() {
return (
<div id="Board">
<button onClick={() => this.createCard()}>Create Card</button>
{this.state.cards.map(card => (
<Card />
))}
</div>
);
}
}
export default class Card extends React.Component {
constructor(props) {
super(props);
this.state = {
active: false
};
}
cardClick = () => {
this.setState({
active: !this.state.active
});
};
render(cardClick) {
return (
<div>
{this.state.active ? (
<div
className="activeCard"
id="card"
onClick={() => this.cardClick()}
>
Active
</div>
) : (
<div
className="inactiveCard"
id="card"
onClick={() => this.cardClick()}
>
Inactive
</div>
)}
</div>
);
}
} ```
答案 0 :(得分:1)
好的,让我们从顶部开始。我想您有一些要渲染为<Card />
的数据,每个数据项一个。您无需将组件保持在状态中,而应将数据保持在状态中。例如:
this.state = {
data: [
{value: 'Cat 1'},
{value: 'Cat 2'},
{value: 'Cat 3'}
]
}
在这种情况下,父级保留数据是正确的。但是,lifting the state up (React docs link)的整个概念并不难。通常,这是一个问题:一个以上的组件是否在乎/取决于相同的状态?如果答案是肯定的,通常父母应该持有它。您的每张卡都保持自己的活动状态是正确的。但是,父母也可以这样做。那样做吧,那么我们将:
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"
的卡片,这很糟糕,ID应该是唯一的。另外,除非您真的需要它,否则可以忽略它。
2)我根据活动卡的索引切换className
。如果当前卡(例如2)也是活动卡,则它将具有activeCard
className。
3)最后,我向孩子传递了一个更新父母状态的函数。通过这样做,我将状态包含在父级中,并且每次更新时,状态也会反映在子级上。这并不是说您为Cards使用基于类的组件的方法是错误的,但是我认为这很简单。
4)WAI-ARIA只是把它扔在那里,并不完全同意具有onClick
个事件的div。为了使Internet成为一个凉爽,易于访问的地方,您可以在div上放置一个role="button"
,以表明它是一个按钮。这还要求它具有可聚焦性以及键盘事件侦听器,在这种情况下,如果元素应该是可单击的,最好使用<button>
。
要回答您的其他问题:
父级自动将所有状态更改传播给所有关心它的子级
所有子组件都独立于父组件,例如,如果它们具有自己的状态,则父组件不在乎。只有当他们共享一个状态和一个状态更新功能时,这才有意义,因此,只有当您专门将此功能传递给子级时,
如果孩子共享一个州,则应将其抬高,这在链接的文档中有解释!
编辑:对于给定的示例,我假设您一次只需要一张活动卡。如果不是这种情况,要么让每张卡都保持其活动状态(如Keno Clayton建议的那样),要么将activeCard
更改为数组,然后根据活动卡的数组检查每张卡的索引
答案 1 :(得分:1)
要回答您的问题:
我在哪里存储单个组件的状态?它是在组件本身中还是在父对象中?
最佳实践是将状态存储在需要它的组件中。如果两个兄弟组件需要访问相同的状态,则将其提升到父状态。
然后您可以使用Context Api传递单个道具或传递整个状态。如果需要,您可以使用它来传递功能以更新父状态,并且子项将在更新时自动接收道具。
对于您的特定情况,每张卡应具有自己的状态,以确定其是否处于活动状态。也可以在父级中保留一系列活动状态,但这不是那么直观,也有点复杂。
如何访问每个组件状态,并告诉它根据另一个子状态的变化而更改?
您不应该这样做。您应该保留要与父级中其他组件共享的任何信息。
答案 2 :(得分:0)
Where do i store the state for the individual component is it in the component itself or is it in the parent?
如果仅在该组件内控制和需要该状态,则单个组件的状态应位于该组件内。例如:Card中的active(boolean)。由于单击卡片应使其处于选中状态,并使当前活动的卡片处于非活动状态,我们可以得出结论,最好将其存储在父级的卡片组件外部。
If it's in the parent how do I pass a function to the child which will update ITS state and not the parents state?
您可以将该函数作为道具传递(绑定到父项之后)
How do I access each of the components state and tell it to change based on another child state changing?
由于您将卡片列表和活动布尔值保留在父级Board组件中,因此不需要这样做。
在董事会中保持这种状态。
this.state = {
cards: [
{id: 1, name: 'Card1'},
{id: 1, name: 'Card2'},
{id: 1, name: 'Card3'},
],
activeId: 2
}