我尝试根据Picker上选择的'Type'从mySQL中获取数据,并使用获取的数据更新ListView。因此,当Picker的onValueChange调用componentDidMount()函数来获取新数据并更新ListView时,我会指定所有内容。
问题是,当我在Picker中选择TypeA时,ListView中的数据不会更新,但是当我第二次在Picker中选择TypeB时,ListView会根据TypeA进行更新。然后,我选择TypeC,基于TypeB更新ListView。
我的代码是否存在问题,或者我使用了错误的方法?
export default class ProfileScreen extends Component {
constructor(props) {
super(props);
this.state = {
TypeInput : 'Vegetarian',
isLoading: true,
};
}
static navigationOptions = {
title: 'View/Edit',
};
OpenSecondActivity(id) {
this.props.navigation.navigate('Second', { ListViewClickItemHolder: id });
}
componentDidMount() {
return fetch('https://unsurfaced-cross.000webhostapp.com/getRecipeRN.php',{
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
RecipeType: this.state.TypeInput
})
}).then((response) => response.json())
.then((responseJson) => {
// Fetch Data update the List View Content
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.setState({
isLoading: false,
dataSource: ds.cloneWithRows(responseJson),
});
})
.catch((error) => {
console.error(error);
});
}
ListViewItemSeparator = () => {
return (
<View
style={{
height: .5,
width: "100%",
backgroundColor: "#000",
}}
/>
);
}
render() {
const { navigate } = this.props.navigation;
if (this.state.isLoading) {
return (
<View style={{flex: 1, paddingTop: 20}}>
<ActivityIndicator />
</View>
);
}
return (
<View style={styles.container}>
<Text style={styles.text}>Recipe Type: </Text>
<Picker
style={{width: 200}}
selectedValue={this.state.TypeInput}
onValueChange={
(itemValue, itemIndex) => {
this.setState({TypeInput: itemValue, isLoading:true})
this.componentDidMount()
this.forceUpdate()
}
}>
<Picker.Item label="Vegetarian" value="Vegetarian" />
<Picker.Item label="Fast Food" value="Fast Food" />
<Picker.Item label="Healthy" value="Healthy" />
<Picker.Item label="No-Cook" value="No-Cook" />
<Picker.Item label="Make Ahead" value="Make Ahead" />
</Picker>
<ListView
dataSource={this.state.dataSource}
renderSeparator= {this.ListViewItemSeparator}
renderRow={(rowData) => <Text style={styles.rowViewContainer}
onPress={this.OpenSecondActivity.bind(this, rowData.RecipeID)}> {rowData.RecipeName} </Text>}
/>
</View>
)
}
}
答案 0 :(得分:1)
您正在手动拨打componentDidMount()
我认为这是错误的做法。
根据文件
安装组件后立即调用
componentDidMount()
。需要DOM节点的初始化应该放在这里。如果需要从远程端点加载数据,这是实例化网络请求的好地方。
在你的情况下,我建议你在改变选择器中的值时,有一些不同的处理函数,它将负责更新状态。您不应手动调用componentDidMount()
,因为它是组件的生命周期挂钩之一。
更多关于Component Lifecycle。
上面的代码现在似乎没问题,在您的代码中,一旦收到更新的数据,您就可以更新ListView的数据源,如下所示,
...
fetch('https://unsurfaced-cross.000webhostapp.com/createRN.php', {
...
.then((responseJson) => {
this.setState({dataSource: responseJson})
}
...
而你ListView
应该是这样的
<ListView
automaticallyAdjustContentInsets={false}
dataSource={ds.cloneWithRows(this.state.dataSource)}
renderRow={(rowData)=> {
return <View>
<Text style={rowStyle.label} content={rowData.someField} />
</View>
}}
...
/>
答案 1 :(得分:0)
似乎处理此问题的更好方法是使用 componentDidUpdate()而不是 componentDidMount()
可以尝试参考下面我已完成的申请。
Github: https://github.com/slnn3r/RecipeRedux.git
上面的项目: