ReactNative開發入門教學(3)-與伺服器溝通(Fetch)

如果我們今天要從伺服器上取得資料的話,我們知道 javascript 有提供 ajax 的寫法,

不過,在 ReactNative 中我們大可不必寫 ajax ,我們可以用 fetch() 來連上我們的伺服器

並取得資料! fetch() 的用法可以參考官網 https://facebook.github.io/react-native/docs/network.html

試試看吧!我想沿用上次的代碼,然後我再伺服器上用PHP架好了一個API,被呼叫後回傳個JSON

內容是「{“Message”:”Clicked!”}」。這樣的話我們先照著官網的方式寫個 fetch() 吧!

import React, { Component } from 'react';
import {
  Text,
  View,
  TouchableHighlight,
  Button,
} from 'react-native';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }
  _click() {
    fetch('https://xxxxxxxxxxxxxxxxxx', {
      method: 'POST',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        Param: 'aaa',
      })
    });
  }
  render() {
    return(
      <View>
        <Button title="Try it!" onPress={this._click.bind(this)}/>
        <TouchableHighlight onPress={this._click.bind(this)}>
          <Text>HelloWorld!</Text>
        </TouchableHighlight>
      </View>
    );
  }
}

export default App;

接著點擊看看會發現沒有任何的反應。是的。因為我們並沒有對傳回的東西做任何的處理。

所以我們在修改一下。

_click() {
  fetch('https://xxxxxxxxxxxxxxxxxx', {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      Param: 'aaa',
    })
  }).then((response) => response.json())
    .then((responseJson) => {
      return responseJson.Message;
    })
    .catch((error) => {
      console.error(error);
    });
}

執行後是否就可以取到伺服器傳回來的JSON值囉!

但是我們大部分會傳一些參數過去給伺服器,例如我要登入某些資料之類的。

在上面會看到有Param這個參數,但那只是我隨便亂打的,伺服器並不會對它有任何

的反應。如果我今天在PHP上想用POST或是GET來收參數的話。用上面的寫法會發現

參數並沒有被傳到伺服器,那是因為我們一般HTML在執行POST或是GET的時候,表頭

並不是json,而是 x-www-form-urlencoded 。這相關的知識我也不懂,也是碰到

這個問題的時候才去查的!所以要把代碼改成如下

_click() {
  fetch('https://xxxxxxxxxxxxxxxxxx', {
    method: 'POST',
    credentials: 'same-origin',
    mode: 'same-origin',
    headers: {
      'Accept':       'application/x-www-form-urlencoded',
      'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: JSON.stringify({
      Param: 'aaa',
    })
  }).then((response) => response.json())
    .then((responseJson) => {
      return responseJson.Message;
    })
    .catch((error) => {
      console.error(error);
    });
}

結果發現改了之後參數還是一樣沒有傳過去,後來繼續上網爬文,得知用

JSON.stringify() 的話並不是像我們平常用的POST或是GET的方式傳給伺服器

所以我們得寫個把參數變成像是 https://xxxxx?Param=aaa 之類的方法。方法

如下 參考:https://stackoverflow.com/questions/31201940/sending-data-as-key-value-pair-using-fetch-polyfill-in-react-native

to_query_string = (obj) => {
  return obj ? Object.keys(obj).sort().map((key) => {
    var val = obj[key];
    if (Array.isArray(val)) {
      return val.sort().map((val2) => {
        return encodeURIComponent(key) + '=' + encodeURIComponent(val2);
      }).join('&');
    }
    return encodeURIComponent(key) + '=' + encodeURIComponent(val);
  }).join('&') : '';
}

然後最後成功的完整代碼會是下面這樣

import React, { Component } from 'react';
import {
  Text,
  View,
  TouchableHighlight,
  Button,
} from 'react-native';

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }
  _click() {
    fetch('https://xxxxxxxxxxxxxxxxxx', {
      method: 'POST',
      credentials: 'same-origin',
      mode: 'same-origin',
      headers: {
        'Accept':       'application/x-www-form-urlencoded',
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      body: to_query_string({
        Param: 'aaa',
      })
    }).then((response) => response.json())
      .then((responseJson) => {
        return responseJson.Message;
      })
      .catch((error) => {
        console.error(error);
      });
  }
  render() {
    return(
      <View>
        <Button title="Try it!" onPress={this._click.bind(this)}/>
        <TouchableHighlight onPress={this._click.bind(this)}>
          <Text>HelloWorld!</Text>
        </TouchableHighlight>
      </View>
    );
  }
}

to_query_string = (obj) => {
  return obj ? Object.keys(obj).sort().map((key) => {
    var val = obj[key];
    if (Array.isArray(val)) {
      return val.sort().map((val2) => {
        return encodeURIComponent(key) + '=' + encodeURIComponent(val2);
      }).join('&');
    }
    return encodeURIComponent(key) + '=' + encodeURIComponent(val);
  }).join('&') : '';
}

export default App;