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

时间:2019-04-29 14:22:08

标签: javascript react-native state

我有一个组件,当我单击图标时,我将执行修改状态的功能,然后可以检查状态并修改图标。在这种情况下,我正在映射数据,它呈现了几个项目。 但是,当我单击一个图标时,所有组件的图标也会更改。

这是组件的代码

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

4 个答案:

答案 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>
                )
            })
        );
    }
}