React-Native如何为每个项目设置不同的状态

问题描述 投票:1回答:4

我有一个组件,当我点击一个图标时,我执行一个修改状态的功能,然后我可以检查状态并修改图标。在那个组件中,我正在映射数据并且它呈现了几个项目。但是,当我点击一个图标时,组件的所有图标也会发生变化。

这是组件的代码

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>
        )
    }
}
javascript react-native state
4个回答
0
投票

您的启动是正确的,但您缺少每个项目的索引。在this.onPressStar()方法内部检查item的index = currentItem。另外不要忘记设置item id = index onpress。

我希望这能让你了解如何处理它。


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)}/>

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,那么你应该弄清楚如何包含它以确保你在map函数和selectedDiscoveries数组中都使用id作为键。

希望有所帮助


0
投票

它现在有效,谢谢。我把马利克和罗德里戈的答案混在一起。

这是我的组件的代码

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>
                )
            })
        );
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.