React Native - 由Picker更新ListView

时间:2018-03-09 06:59:40

标签: android react-native react-native-android

我尝试根据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>
)
}
}

2 个答案:

答案 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

上面的项目:

  • 正在使用Redux Architecture
  • 使用PHP mySQL数据库
  • 使用Stack Navigation