React Native Picker:onValueChange 触发其他选择器的意外 onValueChange
React Native Picker: onValueChange triggers unintended onValueChange for other pickers
我正在尝试实现一个 select 或页面,用户可以在其中 select 基于 3 个位置属性(设施、楼层、套房)的室内地图。这 3 个属性的任何独特组合都保证具有独特的室内地图。我正在使用 React Native 的选择器下拉菜单让用户 select 他们想查看哪个设施、楼层和套房。根据 select 这些属性中的任何一个,它应该过滤其余属性的选项,以便存在有效组合。
过滤列表的算法对我来说不是问题。问题是,当我 select 一个选择器的选择器值时,它将其他选择器的值重置为 defaultPlacholder 值“---”,我不知道为什么。
每个选择器的 selectedValue 等同于存储当前 selected 设施、楼层或套房 ID 的状态变量。状态变量在开始时被初始化为'defaultPlaceholder'。从下拉菜单中选择不同的 ID 会调用 setState 来更改当前 selected ID 的 ID。至少,这是我所期望的。
相反,当从 onValueChange 调用 setState(state variable) 时,组件不会重新渲染一次,而是会重新渲染 MULTIPLE 次(大约 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>
)
我建议您将选择器项生成器放在渲染方法之外,这样您的代码应该类似于以下内容:
(我试过这部分代码,它似乎工作得很好,但我没有实现你的逻辑)
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;
我正在尝试实现一个 select 或页面,用户可以在其中 select 基于 3 个位置属性(设施、楼层、套房)的室内地图。这 3 个属性的任何独特组合都保证具有独特的室内地图。我正在使用 React Native 的选择器下拉菜单让用户 select 他们想查看哪个设施、楼层和套房。根据 select 这些属性中的任何一个,它应该过滤其余属性的选项,以便存在有效组合。
过滤列表的算法对我来说不是问题。问题是,当我 select 一个选择器的选择器值时,它将其他选择器的值重置为 defaultPlacholder 值“---”,我不知道为什么。
每个选择器的 selectedValue 等同于存储当前 selected 设施、楼层或套房 ID 的状态变量。状态变量在开始时被初始化为'defaultPlaceholder'。从下拉菜单中选择不同的 ID 会调用 setState 来更改当前 selected ID 的 ID。至少,这是我所期望的。
相反,当从 onValueChange 调用 setState(state variable) 时,组件不会重新渲染一次,而是会重新渲染 MULTIPLE 次(大约 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>
)
我建议您将选择器项生成器放在渲染方法之外,这样您的代码应该类似于以下内容:
(我试过这部分代码,它似乎工作得很好,但我没有实现你的逻辑)
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;