React Native Picker: onValueChange запускает непреднамеренное onValueChange для других сборщиков - PullRequest
0 голосов
/ 16 октября 2018

Я пытаюсь реализовать страницу селектора, на которой пользователь может выбрать карту внутреннего пространства на основе 3 атрибутов местоположения (объект, этаж, люкс).Любая уникальная комбинация этих 3 атрибутов гарантированно будет иметь уникальную внутреннюю карту.Я использую выпадающее меню React Native Picker, чтобы пользователь мог выбрать, какие объекты, этажи и апартаменты они хотели бы просмотреть.При выборе любого из этих атрибутов он должен отфильтровать параметры оставшихся атрибутов так, чтобы существовала допустимая комбинация.

Алгоритм фильтрации списков для меня не проблема.Проблема состоит в том, что когда я выбираю значение средства выбора для одного из средств выбора, оно сбрасывает значения для других средств выбора в значение defaultPlacholder '---', и я не могу понять, почему.

selectedValue для каждогоВыбор средств эквивалентен переменным состояния, в которых хранится выбранный в данный момент объект, этаж или номер комплекта.Переменные состояния вначале инициализируются как defaultPlaceholder.Выбор другого идентификатора из выпадающего меню вызывает setState, чтобы изменить идентификатор выбранного в данный момент идентификатора.По крайней мере, это то, что я ожидал.

Вместо этого, когда setState ( переменная состояния ) вызывается из onValueChange, вместо повторного рендеринга один раз, компонент выполняет повторное рендеринг несколько раз (около6-7).Переменная состояния изменяется на желаемый выпадающий элемент для одной итерации рендеринга, а затем автоматически сбрасывается до значения 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 голосов
/ 16 октября 2018

Я предлагаю вам вывести генераторы элементов выбора за пределы метода рендеринга, чтобы ваш код выглядел примерно так:

(я пробовал эту часть кода, и она работает нормально, но я не реализуюваша логика)

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;
...