我有一个组件,当我单击图标时,我将执行修改状态的功能,然后可以检查状态并修改图标。在这种情况下,我正在映射数据,它呈现了几个项目。 但是,当我单击一个图标时,所有组件的图标也会更改。
这是组件的代码
export default class DiscoveryComponent extends Component {
constructor(props) {
super(props)
this.state = {
starSelected: false
};
}
static propTypes = {
discoveries: PropTypes.array.isRequired
};
onPressStar() {
this.setState({ starSelected: !this.state.starSelected })
}
render() {
return (
this.props.discoveries.map((discovery, index) => {
return (
<Card key={index} style={{flex: 0}}>
<CardItem>
<TouchableOpacity style={[styles.star]}>
<Icon style={[styles.iconStar]} name={(this.state.starSelected == true)?'star':'star-outline'} onPress={this.onPressStar.bind(this)}/>
</TouchableOpacity>
</CardItem>
</Card>
)
})
);
}
}
这是使用该组件的屏幕代码
export default class DiscoveryItem extends Component {
constructor(props) {
super(props);
this.state = {
discoveries: [],
loading: true
};
}
componentDidMount() {
firebase.database().ref("discoveries/").on('value', (snapshot) => {
let data = snapshot.val();
let discoveries = Object.values(data);
this.setState({discoveries: discoveries, loading: false});
});
}
render() {
return (
<Container>
<Content>
<DiscoveryComponent discoveries={this.state.discoveries} />
</Content>
</Container>
)
}
}
答案 0 :(得分:0)
您的初始化是正确的,但是您缺少每个项目的索引。在this.onPressStar()
方法内部,检查项目的索引是否= currentItem。另外,别忘了设置项目ID =印刷索引。
我希望这能使您知道如何处理它。
答案 1 :(得分:0)
您必须将星星变成一个数组并为其编索引:
更改您的构造函数:
constructor(props) {
super(props)
this.state = {
starSelected: []
};
}
将onPressStar函数更改为:
onPressStar(index) {
this.setState({ starSelected[index]: !this.state.starSelected })
}
和您的图标
<Icon style={[styles.iconStar]} name={(this.state.starSelected[index] == true)?'star':'star-outline'} onPress={()=>this.onPressStar(index)}/>
答案 2 :(得分:0)
好吧,问题在于您只有一个'starSelected'值,您的地图函数中的所有渲染项都在监听。因此,当一个人成为事实时,所有人都成为事实。
您可能应该在顶层组件中保持选定状态,并向下传递发现,是否选择发现以及如何将被选择为道具切换到每个发现的呈现功能。
export default class DiscoveryItem extends Component {
constructor(props) {
super(props);
this.state = {
discoveries: [],
selectedDiscoveries: [] // NEW
loading: true
};
}
toggleDiscovery = (discoveryId) => {
this.setState(prevState => {
const {selectedDiscoveries} = prevstate
const discoveryIndex = selectedDiscoveries.findIndex(id => id === discoveryId)
if (discoveryIndex === -1) { //not found
selectedDiscoveries.push(discoveryId) // add id to selected list
} else {
selectedDiscoveries.splice(discoveryIndex, 1) // remove from selected list
}
return {selectedDiscoveries}
}
}
componentDidMount() {
firebase.database().ref("discoveries/").on('value', (snapshot) => {
let data = snapshot.val();
let discoveries = Object.values(data);
this.setState({discoveries: discoveries, loading: false});
});
}
render() {
return (
<Container>
<Content>
{
this.state.discoveries.map(d => {
return <DiscoveryComponent key={d.id} discovery={d} selected={selectedDiscoveries.includes(d.id)} toggleSelected={this.toggleDiscovery} />
//<DiscoveryComponent discoveries={this.state.discoveries} />
</Content>
</Container>
)
}
}
然后,您可以使用DiscoveryComponent为每个对象进行渲染,现在您将状态保持在顶层,并向下传递发现(如果已选择),并将切换功能作为道具。
此外,我认为您也许可以从firebase中获取snapshot.docs()
(我不确定,因为我使用的是firestore),然后可以确保值中包含文档ID。如果snapshot.val()不包含ID,那么您应该弄清楚如何包括该ID,以确保在映射函数和selectedDiscoveries数组中都将ID用作键。
希望有帮助
答案 3 :(得分:0)
现在可以了,谢谢。 我在Malik和Rodrigo的回答之间混在一起。
这是我组件的代码
export default class DiscoveryComponent extends Component {
constructor(props) {
super(props)
this.state = {
tabStarSelected: []
};
}
static propTypes = {
discoveries: PropTypes.array.isRequired
};
onPressStar(index) {
let tab = this.state.tabStarSelected;
if (tabStar.includes(index)) {
tabStar.splice( tabStar.indexOf(index), 1 );
}
else {
tabStar.push(index);
}
this.setState({ tabStarSelected: tab })
}
render() {
return (
this.props.discoveries.map((discovery, index) => {
return (
<Card key={index} style={{flex: 0}}>
<CardItem>
<Left>
<Body>
<Text note>{discovery.category}</Text>
<Text style={[styles.title]}>{discovery.title}</Text>
</Body>
</Left>
<TouchableOpacity style={[styles.star]}>
<Icon style={[styles.iconStar]} name={(this.state.tabStarSelected[index] == index)?'star':'star-outline'} onPress={()=>this.onPressStar(index)}/>
</TouchableOpacity>
</CardItem>
</Card>
)
})
);
}
}