【问题标题】:How to setState of a particular index in an array React Native如何在数组 React Native 中设置特定索引的状态
【发布时间】:2023-04-02 05:28:01
【问题描述】:

我有一个对象数组,我当前正在映射这些对象以生成按钮。单击时,我希望用户单击以更改颜色的特定按钮的背景颜色(我希望它像开关一样打开,因此我最终可以保存到异步存储中)。现在,当用户单击时,所有按钮都会改变颜色。我不太确定应该如何在 selectMetric 函数中处理 this.setState。

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;

【问题讨论】:

    标签: reactjs react-native setstate


    【解决方案1】:

    所以对您的问题的简短回答如下所示:

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

    它涉及将整个按钮阵列置于状态,因为这些按钮的状态是可以改变的。您还可以将标志保持为状态数组,并将按钮信息保持为单独的常量

    此解决方案使用 cloneDeep(来自 lodash)来防止代码改变对象的状态,但您也可以使用 this.state.data.map 并创建新对象(只要您的对象没有深度嵌套就可以) )。

    如果你使用 Redux,列表可能会作为 props 进入组件,然后 selectMetric 将调度一个操作来更新 Redux 中的标志。

    【讨论】:

    • 谢谢加勒特,真的很有帮助!
    • 我注意到它不能很好地适应数据集 (20+)。更改颜色时,该按钮有大约一秒钟的延迟。关于这个组件的可扩展性的任何提示?
    • 我会尝试使用 FlatList 而不是 Array 上的 ScrollView/map。如果您在 Array 上进行映射,则每次更改都会重新渲染整个事物。 FlatList 进行了优化以防止不必要的渲染。
    【解决方案2】:

    对于查看此帖子的其他人,上面的答案非常有帮助。最后补充几点,如果你想让按钮亮起来,我添加了一个简单的 if else 到 selectMetric:

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

    并更新了 showMetric 中 Button 的 backgroundColor 属性:

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

    【讨论】:

      猜你喜欢
      • 2021-02-22
      • 2021-12-28
      • 2019-06-27
      • 1970-01-01
      • 2018-03-21
      • 1970-01-01
      • 2021-12-18
      • 2020-04-29
      • 2019-01-16
      相关资源
      最近更新 更多