React Native Picker:onValueChange触发其他选择器意外的onValueChange

时间:2018-10-16 17:27:30

标签: android react-native picker

我正在尝试实现一个选择器页面,用户可以在其中基于3个位置属性(设施,楼层,套房)选择室内地图。这3个属性的任何唯一组合都可以保证具有唯一的室内地图。我正在使用React Native的Picker下拉菜单供用户选择他们想要查看的设施,楼层和套房。在选择这些属性中的任何一个时,它应该过滤其余属性的选项,以便存在有效的组合。

过滤列表的算法对我来说不是问题。问题是,当我为其中一个选择器选择一个选择器值时,它将其他选择器的值重置为defaultPlacholder值'---',我无法弄清原因。

每个选择器的selectedValue等同于存储当前所选设施,楼层或套件ID的状态变量。状态变量一开始被初始化为“ defaultPlaceholder”。从下拉菜单中选择其他ID会调用setState更改当前选定ID的ID。至少这是我所期望的。

相反,当从onValueChange调用setState(状态变量)时,组件将重新渲染多次(而不是重新渲染一次),而不是重新渲染一次。状态变量将更改为所需的下拉项,以进行一次渲染迭代,然后自动重置为defaultPlaceholder值。不仅如此,即使某些选择器的状态变量没有更改,它也以某种方式触发了其他选择器的onValueChange,只有选择器项列表(例如pickerFacilitiesList)发生了变化。现在,无论之前的状态值是什么,其他选择器项都将重置为defaultPlaceholder值。

更令人困惑的是,套件选择器不会发生此问题,只有设施选择器和楼层选择器才会发生此问题。

任何帮助将不胜感激。

下面:render()函数的一部分

    //.map iterates through uniqueFacilityIDs and generates a list of picker items
    const pickerFacilitiesList = uniqueFacilityIDs.map(a => {
      return <Picker.Item key={a.key} label={a.facilityName} value={a.facilityID} />;
    });    

    const pickerFloorsList = uniqueFloorIDs.map(a => {
      return <Picker.Item key={a.key} label={a.floorName} value={a.floorID} />;
    });

    const pickerSuitesList = uniqueSuiteIDs.map(a => {
      return <Picker.Item key={a.key} label={a.suiteName} value={a.suiteID} />;
    });


    if(this.state.pickerFacilityID === defaultPlaceholder || this.state.pickerFloorID === defaultPlaceholder || this.state.pickerSuiteID === defaultPlaceholder){
      return (
        <View>
          <Text style={{fontSize: 18, fontWeight: 'bold', textAlign: 'center', marginBottom: 25, marginTop: 15}}> Display Assets by Suites </Text> 

          <Text style={{fontSize: 16.5, textAlign: 'left', marginLeft: 30, marginBottom: 15, textDecorationLine: 'underline'}}>Filter suites by:</Text>

          <Text style={{fontSize: 16.5, textAlign: 'left', marginLeft: 30}}> Facility </Text>
          <Picker
            mode = 'dropdown'
            style = {{width: '80%', marginLeft: 30}}
            selectedValue={this.state.pickerFacilityID}
            onValueChange={(itemValue, itemIndex) => {
              this.setState({pickerFacilityID:itemValue})
            }}
          >
            <Picker.Item label = {defaultPlaceholder} value = {defaultPlaceholder}/>
            {pickerFacilitiesList}
          </Picker>  

          <Text style={{fontSize: 16.5, textAlign: 'left', marginLeft: 30}}> Floor </Text>
          <Picker
            mode = 'dropdown'
            style = {{width: '80%', marginLeft: 30}}
            selectedValue={this.state.pickerFloorID}
            onValueChange={(itemValue, itemIndex) => {
              this.setState({pickerFloorID:itemValue})
            }}
          >
            <Picker.Item label = {defaultPlaceholder} value = {defaultPlaceholder} />
            {pickerFloorsList}
          </Picker>

          <Text style={{fontSize: 16.5, textAlign: 'left', marginLeft: 30}}> Suite </Text>
          <Picker
            mode = 'dropdown'
            style = {{width: '80%', marginLeft: 30}}
            selectedValue={this.state.pickerSuiteID}
            onValueChange={(itemValue, itemIndex) => {
              this.setState({pickerSuiteID:itemValue})
            }}
          >
            <Picker.Item label = {defaultPlaceholder} value = {defaultPlaceholder} />
            {pickerSuitesList}
          </Picker>

          <TouchableHighlight 
            style={{ backgroundColor: 'gray', left: 200, width: 165, height: 40, justifyContent: 'center', alignItems: 'center', top: 10}}  
            activeOpacity = {1}
            onPress={() => {
              //Go to render map component 
            }}  
          >    
            <Text style = {{color: '#FFFFFF', fontSize: 18}}> Display suite map </Text>
          </TouchableHighlight>        
        </View>
      )

1 个答案:

答案 0 :(得分:0)

我建议您将选择器项目生成器置于render方法之外,这样您的代码应类似于以下内容:

(我尝试了这部分代码,看起来工作正常,但我没有实现您的逻辑)

import React from 'react';
import {
  View,
  Text,
  Picker,
  TouchableHighlight,
  ScrollView,
} from 'react-native';

const defaultPlaceholder = 'default placeholder';

const uniqueFacilityIDs = [
  {
    key: 'facility_key_1',
    facilityName: 'Facility Name 1',
    facilityID: 'facility_id_1'
  },
  {
    key: 'facility_key_2',
    facilityName: 'Facility Name 2',
    facilityID: 'facility_id_2'
  },
];

const uniqueFloorIDs = [
  {
    key: 'floor_key_1',
    floorName: 'Floor Name 1',
    floorID: 'floor_id_1'
  },
  {
    key: 'floor_key_2',
    floorName: 'Floor Name 2',
    floorID: 'floor_id_2'
  },
];

const uniqueSuiteIDs = [
  {
    key: 'suits_key_1',
    suiteName: 'Suits Name 1',
    suiteID: 'suits_id_1'
  },
  {
    key: 'suits_key_2',
    suiteName: 'Suits Name 2',
    suiteID: 'suits_id_2'
  },
];

class App extends React.Component {
  state = {
    pickerFacilityID: defaultPlaceholder,
    pickerFloorID: defaultPlaceholder,
    pickerSuiteID: defaultPlaceholder,
  };

  renderFacilitiesPickerItems = () => uniqueFacilityIDs.map(a => {
    return <Picker.Item key={a.key} label={a.facilityName} value={a.facilityID}/>;
  });

  renderFloorsPickerItems = () => uniqueFloorIDs.map(a => {
    return <Picker.Item key={a.key} label={a.floorName} value={a.floorID}/>;
  });

  renderSuitesPickerItems = () => uniqueSuiteIDs.map(a => {
    return <Picker.Item key={a.key} label={a.suiteName} value={a.suiteID}/>;
  });

  render() {
    if (this.state.pickerFacilityID === defaultPlaceholder || this.state.pickerFloorID === defaultPlaceholder || this.state.pickerSuiteID === defaultPlaceholder) {
      return (
          <ScrollView>
            <View>
              <Text style={{
                fontSize: 18,
                fontWeight: 'bold',
                textAlign: 'center',
                marginBottom: 25,
                marginTop: 15
              }}> Display Assets by Suites </Text>

              <Text style={{
                fontSize: 16.5,
                textAlign: 'left',
                marginLeft: 30,
                marginBottom: 15,
                textDecorationLine: 'underline'
              }}>Filter suites by:</Text>

              <Text style={{fontSize: 16.5, textAlign: 'left', marginLeft: 30}}> Facility </Text>
              <Picker
                  mode='dropdown'
                  style={{width: '80%', marginLeft: 30}}
                  selectedValue={this.state.pickerFacilityID}
                  onValueChange={(itemValue, _itemIndex) => {
                    this.setState({pickerFacilityID: itemValue})
                  }}
              >
                <Picker.Item label={defaultPlaceholder} value={defaultPlaceholder}/>
                {this.renderFacilitiesPickerItems()}
              </Picker>

              <Text style={{fontSize: 16.5, textAlign: 'left', marginLeft: 30}}> Floor </Text>
              <Picker
                  mode='dropdown'
                  style={{width: '80%', marginLeft: 30}}
                  selectedValue={this.state.pickerFloorID}
                  onValueChange={(itemValue, itemIndex) => {
                    this.setState({pickerFloorID: itemValue})
                  }}
              >
                <Picker.Item label={defaultPlaceholder} value={defaultPlaceholder}/>
                {this.renderFloorsPickerItems()}
              </Picker>

              <Text style={{fontSize: 16.5, textAlign: 'left', marginLeft: 30}}> Suite </Text>
              <Picker
                  mode='dropdown'
                  style={{width: '80%', marginLeft: 30}}
                  selectedValue={this.state.pickerSuiteID}
                  onValueChange={(itemValue, itemIndex) => {
                    this.setState({pickerSuiteID: itemValue})
                  }}
              >
                <Picker.Item label={defaultPlaceholder} value={defaultPlaceholder}/>
                {this.renderSuitesPickerItems()}
              </Picker>
            </View>
          </ScrollView>
      )
    } else {
      return (
          <TouchableHighlight
              style={{
                backgroundColor: 'gray',
                left: 200,
                width: 165,
                height: 40,
                justifyContent: 'center',
                alignItems: 'center',
                top: 10
              }}
              activeOpacity={1}
              onPress={() => {
                //Go to render map component
              }}
          >
            <Text style={{color: '#FFFFFF', fontSize: 18}}> Display suite map </Text>
          </TouchableHighlight>
      )
    }
  }
}

export default App;