所有动态旋转器React-native的所选值索引保持不变

时间:2018-04-02 08:05:36

标签: react-native modal-dialog react-redux react-modal

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

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

任何人都可以告诉我如何实现这一目标吗?我已经在这2天过去了。请让我知道你的建议,这对我很有帮助。

这是我的代码: -

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

非常感谢您的帮助!!!

问候

2 个答案:

答案 0 :(得分:1)

当新状态取决于之前的状态时,您应该使用格式setState((prevState,props)=&gt; {})参见docs中的引用。在任何方面你都不应该直接改变状态,这就是这行选择的值[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};
  });
}

答案 1 :(得分:0)

您的问题是name是父母组件状态的一部分。每当调用onClickColor时,父母组件都会更新,强制所有微调器随之重新渲染。

由于您的问题有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。如果该组件中的任何部分需要该信息,您应该创建一个可供商店访问的额外子组件。