2017-07-13 1 views
0

J'ai un tableau d'objets que je suis en train de mapper pour générer des boutons. Lorsque je clique dessus, je veux que la couleur d'arrière-plan du bouton spécifique sur lequel l'utilisateur clique change de couleur (je veux qu'il bascule, comme un commutateur, pour que je puisse éventuellement enregistrer dans un stockage asynchrone). En ce moment, lorsque l'utilisateur clique, tous les boutons changent de couleur. Je ne sais pas comment gérer this.setState dans la fonction selectMetric.Comment définir l'état d'un index particulier dans un tableau React Native

import React, {Component} from 'react'; 
import {View, Text, ScrollView} from 'react-native'; 
import {Button} from 'react-native-elements'; 

const RISK_DATA = [ 
    {id: 1, text: 'cats', flag: false, buttonColor: null}, 
    {id: 2, text: 'dogs', flag: false, buttonColor: null}, 

] 


class IssueSelectionScreen extends Component { 

    state = {flag: false, buttonColor: null} 

    selectMetric = (index) => { 

    for (let i=0; i < RISK_DATA.length; i++) { 

     if (index === (RISK_DATA[i].id - 1)) { 

     console.log("RISK_DATA:", RISK_DATA[i]); // logs matching id 

// ------------------------------------------------------ 
// Problem setting correct state here: 

     RISK_DATA[i].buttonColor = this.setState({flag: true, buttonColor: '#03A9F4'}) 

     // this.setState({flag: true, buttonColor: '#03A9F4'}) 
     // this.setState({update(this.state.buttonColor[i], {buttonColor: {$set: '#03A9F4'}}) }) 


// ---------------------------------------------------------- 
     } 
    } 
    } 

    showMetric() { 
    return RISK_DATA.map((metric, index) => { 
     return (
     <View key={metric.id}> 
      <Button 
      raised 
      color={'black'} 
      title={metric.text} 
      borderRadius={12} 
      onPress={() => this.selectMetric(index)} 
      backgroundColor={this.state.buttonColor} 
      > 
      {metric.text} 
      </Button> 
      <Text>{/* intentionally blank*/} </Text> 
     </View> 
    ) 
    }) 
    } 

    render() { 
    return(
     <ScrollView style={styles.wrapper}> 
     <View style={styles.issues}> 
      {this.showMetric()} 
     </View> 
     </ScrollView> 
    ); 
    } 
} 


const styles = { 
    issues: { 
    justifyContent: 'center', 
    flexDirection: 'row', 
    flexWrap: 'wrap', 
    alignItems: 'flex-start', 
    marginTop: 10, 
    justifyContent: 'space-between', 
    }, 
    wrapper: { 
    backgroundColor: '#009688' 
    } 
} 

export default IssueSelectionScreen; 

Répondre

0

donc la réponse courte à votre question ressemblerait à quelque chose comme ceci:

class IssueSelectionScreen extends Component { 
    constructor(props) { 
    super(props); 
    this.state = { 
     data: cloneDeep(RISK_DATA), 
    }; 
    } 

    selectMetric = (index) => { 
    const tempData = cloneDeep(this.state.data); 
    tempData[index].flag = !tempData[index].flag; 
    this.setState({ data: tempData }); 
    } 

    showMetric() { 
    return this.state.data.map((metric, index) => { 
     // same 
    }) 
    } 

    render() { 
    // same 
    } 
} 

Il consiste à mettre tout l'éventail des boutons dans l'état depuis l'état de ces boutons est ce qui peut changer. Vous pouvez également conserver les drapeaux en tant que tableau dans l'état et conserver l'info du bouton comme une constante séparée

Cette solution utilise cloneDeep (de lodash) pour empêcher le code de muter l'état des objets mais vous pourriez probablement le faire aussi avec this.state.data.map et en créant de nouveaux objets (ce qui fonctionne tant que vos objets ne sont pas profondément imbriqués).

Si vous utilisez Redux, la liste entrerait probablement dans le composant en tant que prop, alors selectMetric enverrait une action pour mettre à jour l'indicateur dans Redux.

+0

Merci Garrett, vraiment utile! – whosbuddy

+0

J'ai remarqué qu'il ne s'adapte pas bien aux jeux de données (20+). Le bouton a environ une seconde de retard lors du changement de couleur. Des conseils sur l'évolutivité pour ce composant? – whosbuddy

+0

J'essaierais un FlatList au lieu d'un ScrollView/map sur Array. Si vous faites une carte sur le tableau, la chose entière se re-rend pour chaque changement. FlatList a des optimisations pour éviter les rendus inutiles. –

0

Pour tous ceux qui consultent ce post, la réponse ci-dessus est très utile. Pour ajouter quelques remarques dernières, si vous essayez d'obtenir les boutons pour allumer j'ai ajouté un simple si d'autre à selectMetric:

if (tempData[index].flag) { 
    tempData[index].buttonColor = '#03A9F4'; 
    console.log('tempData true:', tempData); 
} else { 
    tempData[index].buttonColor = null; 
    console.log('tempData false:', tempData); 
} 

et mis à jour la propriété backgroundColor sur le bouton en showMetric avec:

backgroundColor={this.state.data[index].buttonColor}