我有一个组件,当我点击一个图标时,我执行一个修改状态的功能,然后我可以检查状态并修改图标。在那个组件中,我正在映射数据并且它呈现了几个项目。但是,当我点击一个图标时,组件的所有图标也会发生变化。
这是组件的代码
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>
)
}
}
您的启动是正确的,但您缺少每个项目的索引。在this.onPressStar()
方法内部检查item的index = currentItem。另外不要忘记设置item id = index onpress。
我希望这能让你了解如何处理它。
你必须把你的星星变成一个数组并索引它们:
改变你的构造函数:
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)}/>
好吧,问题是你有一个'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,那么你应该弄清楚如何包含它以确保你在map函数和selectedDiscoveries数组中都使用id作为键。
希望有所帮助
它现在有效,谢谢。我把马利克和罗德里戈的答案混在一起。
这是我的组件的代码
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>
)
})
);
}
}