所选值的索引对于所有动态微调器 React-native 保持不变

Index of selected value remains same for all dynamic spinners React-native

我正在尝试制作动态屏幕,其中我在 react-native 中使用 forEach 循环添加多个 CustomSpinners

我面临的问题是,每当我从任何微调器中 selecting 值时,所有微调器的值都会更新,因为索引保持不变。假设当我单击颜色微调器并选择位于索引 2 的 Cyna 时,当我键入 this.setState({name: index}); 时它再次调用 Render 方法并且整个视图再次绘制并且因为 itemName={this.state.name} 设置为 2 所以它将根据索引 2 自动 select 所有微调器值,这是我想要的,当我点击颜色微调器并选择青色时,只会更新该颜色微调器,而不是更新同一索引处的所有微调器。

任何人都可以告诉我如何实现这一目标吗?在过去的两天里,我已经为此挠头了。请让我知道您的建议,这将对我有很大帮助。

这是我的代码 :-

onClickColor(data) {
  this.setState({ name: index });
}   

renderSpinerData(item) {
  return <CustomDynamicSpinner
           title={"Chosse  " + item.label}
           listArray={item.options}
           onClick={(data,index) => this.onClickDropdown(data,index)}
           itemName={this.state.name}
           btnStyle={{
             height: 42,
             marginBottom: 2,
             borderBottomWidth: 1 / 2,
             justifyContent: "center"
           }}
           txtColor={appColor.lightGrey}
           style={{
             height: 42,
             marginBottom: 2,
             borderBottomWidth: 1 / 2
           }}
           closeIconButtonStyle={styles.closeButtonStyle}
         />
       }; 

    renderConfigurableProductDetail() {
      let array=[];
      if (CustomConfigArray.length>0){
        array = CustomConfigArray;
      } else {
        array = this.props.ProductDetailState.productData.configurable;
      }
      {
        return array.map((item) => {
          if(item.label!="Size"){
            return (
              <View style={{ flex: 1, backgroundColor: "white", flexDirection: "column", marginTop: 8 }}>
                <CustomText style={{ fontSize: 16, fontFamily: "futuraLigtBt", marginLeft: 6, paddingLeft: 15, paddingRight: 15, paddingTop: 5, paddingBottom: 5 }}>
                  {item.label}
                </CustomText>
                {this.renderSpinerData(item)}
              </View>;
            )
          }
        })
      }
    };

我的 CustomSpiner class :-

  class DynamicListViewModal extends Component {
    constructor(props) {
    super(props);

    this.state = {
      dataSource: ds.cloneWithRows(this.props.listArray),
      listArray: this.props.listArray
    };
    this.handleClick = this.handleClick.bind(this);
    this.renderRow = this.renderRow.bind(this);
    this.renderList = this.renderList.bind(this);
  }
  handleClick(data, index) {
    this.props.onClick(data, index);
    this.props.onClose();
  }
  renderRow(rowData) {
    const separatorStyle = this.props.separatorStyle;
    const rowTextStyle = this.props.rowText;
    const rowStyle = this.props.rowStyle;
    const rowId = this.props.listArray.indexOf(rowData);
    let separator = <View style={separatorStyle} />;

    let row = (
      <View style={rowStyle}>
        <Text style={rowTextStyle}>{rowData.label}</Text>
      </View>
    );

    if (this.props.renderRow) {
      row = this.props.renderRow(rowData, rowId);
    }

    return (
      <View>
        <TouchableOpacity onPress={() => this.handleClick(rowData, rowId)}>
          {row}
        </TouchableOpacity>
        {separator}
      </View>
    );
  }
  renderList() {
    const listViewStyle = this.props.listViewStyle || DefaultStyles.listView;
    return (
      <ListView
        style={listViewStyle}
        dataSource={this.state.dataSource}
        renderRow={(rowData) => this.renderRow(rowData)}
        automaticallyAdjustContentInsets={false}
        enableEmptySections={true}
      />
    );
  }
  render() {
    const containerStyle = this.props.containerStyle;
    const topBarStyle = this.props.topBarStyle;
    const iconContainerStyle = this.props.iconContainerStyle;
    const closeIconButtonStyle = this.props.closeIconButtonStyle;
    const titleStyle = this.props.titleStyle;
    const title = this.props.title;

    return <View style={containerStyle}>
      <View style={topBarStyle}>
        <View style={iconContainerStyle} />
        <Text style={[titleStyle, { fontWeight: "bold", fontSize: 17 }]}>
          {title}
        </Text>
        <TouchableOpacity style={iconContainerStyle} onPress={() => this.props.onClose()}>
          <Image source={require("../../assets/cancel.png")} style={closeIconButtonStyle} />
        </TouchableOpacity>
      </View>
      {this.renderList()}
    </View>;
  }
}

class CustomDynamicSpinner extends Component {
  constructor(props) {
    super(props);

    this.state = {
      data: this.props.data,
      popoverIsOpen: false
    };

    this.onClick = this.onClick.bind(this);
  }
  onClick(data) {
    console.log("selected data:", data);
  }
  render() {
    const onClick = this.props.onClick || this.onClick;
    return <View>
      <TouchableOpacity style={this.props.btnStyle} onPress={() => this.setState(
        { popoverIsOpen: true }
      )}>
        <Text style={{ color: this.props.txtColor }}>
          {(this.props.itemName!="value" || this.props.itemName == 0) ? this.props.listArray[this.props.itemName].label : "Please select"}
        </Text>
      </TouchableOpacity>
      <Modal animationType={"slide"} transparent={false} visible={this.state.popoverIsOpen} onRequestClose={() => {
        console.log("Modal has been closed.");
      }}>
        <View>
          <DynamicListViewModal listArray={this.props.listArray} title={this.props.title} onClick={onClick} onClose={() => this.setState(
            { popoverIsOpen: false }
          )} containerStyle={this.props.containerStyle} listViewStyle={this.props.listViewStyle} separatorStyle={this.props.separatorStyle} topBarStyle={this.props.topBarStyle} titleStyle={this.props.titleStyle} iconContainerStyle={this.props.iconContainerStyle} closeIconButtonStyle={this.props.closeIconButtonStyle} rowTextStyle={this.props.rowTextStyle} rowStyle={this.props.rowStyle} />
        </View>
      </Modal>
    </View>;
  }
}

来自Api的回应:-

 "configurable": [{
              "id": "142",
              "code": "size",
              "label": "Size",
              "options": [{
                "attribute_id": "142",
                "atribute_code": "size",
                "id": "171",
                "label": "XL",
                "products": [
                  "2071",
                  "2074"
                ]
              }, {
                "attribute_id": "142",
                "atribute_code": "size",
                "id": "172",
                "label": "L",
                "products": [
                  "2072"
                ]
              }]
            },
            {
              "id": "93",
              "code": "color",
              "label": "Color",
              "options": [{
                "attribute_id": "93",
                "atribute_code": "color",
                "id": "50",
                "label": "Blue",
                "products": [
                  "2071"
                ]
              },
              {
                "attribute_id": "93",
                "atribute_code": "color",
                "id": "60",
                "label": "Black",
                "products": [
                  "2072"
                ]
              }, {
                "attribute_id": "93",
                "atribute_code": "color",
                "id": "64",
                "label": "Cyna",
                "products": [
                  "2072"
                ]
              }, {
                "attribute_id": "93",
                "atribute_code": "color",
                "id": "61",
                "label": "White",
                "products": [
                  "2071",
                  "2074"
                ]
              }
              ]
            },
            {
              "id": "148",
              "code": "format",
              "label": "Format",
              "options": [{
                "attribute_id": "148",
                "atribute_code": "format",
                "id": "102",
                "label": "Download",
                "products": [
                  "2072",
                  "2071",
                  "2074"
                ]
              },
              {
                "attribute_id": "148",
                "atribute_code": "format",
                "id": "103",
                "label": "File",
                "products": [
                  "2071",
                  "2074"
                ]
              }
              ]
            }
            ]

非常感谢您的帮助!!!

此致

您的问题是 name 是父组件状态的一部分。每当调用 onClickColor 时,父组件都会更新,迫使所有微调器一起 re-render。

由于你的问题有 react-redux 标签,我假设你的应用程序也使用 redux。如果是这样,那么最简单的解决方案是将 name 移动到 redux 的存储中,让 CustomDynamicSpinner 直接从存储中读取 name

import { connect } from 'react-redux'

...

const mapStateToProps = (state) => ({
  itemName: state.whateverPath.name
}) 

connect(mapStateToProps)(CustomDynamicSpinner)

并且不要让包含 CustomDynamicSpinner 的组件从 redux 的商店中读取 name。如果该组件中的任何部分都需要该信息,您应该创建一个商店可以访问的额外子组件。

当新状态依赖于之前的状态时,您应该使用格式 setState((prevState, props) => {}) 参见 docs 中的参考。无论如何你都不应该直接改变状态,这就是这一行所做的 selectValue[index] = value 因为 selectValue 只是对 this.state

的引用

所以这正是您需要做的:-

// load selectedDropDownValue data from state with the item's id
// pass the item value to the change function
<Picker
  selectedValue={this.state.selectedDropDownValue[item.id]}
  onValueChange={(itemValue, itemIndex) => this.onClickDropdown(itemValue, itemIndex, item)}
>
  {this.loadData(item)}
</Picker>

onClickDropdown(data, index, item){
  // save each items selected data with their id
  this.setState((prevState) => {
    const value = Object.assign({}, prevState.selectedDropDownValue, { [item.id]: data});
    return { selectedDropDownValue: value};
  });
}