このページの目標
- [ ] Fetch APIを使ってHttpリクエストが扱えるようになる
- [ ] FlatListを使ってリスト表示が出来るようになる
- [ ] APIレスポンスをFlatListでリストを表示する実装が出来るようになる
Fetch API
Fetch APIとは
- 現代のXMLHttpRequestのようなもの
- WHATWGによって標準化され、ほとんどのモダンブラウザで利用可能
- ReactNativeでも同様のインターフェースで使える
https://developer.mozilla.org/ja/docs/Web/API/Fetch_API/Using_Fetch
GET
const response = await fetch('https://example.com/images/1');
POST
const request = { method: 'POST', headers: { Accept: 'application/json', 'content-type': 'application/json', }, body: JSON.stringify({image: base64String}), }; const response = await fetch('https://example.com/images', request)
Responseを扱う
エラー時(4xx,5xx)も例外を吐かないので正常なやり取りが出来たか始めに確認する必要があります。
if(response.ok) { //200系が返ってきていることを確認 return await response.json(); //レスポンス内容は非同期で受け取る }
https://developer.mozilla.org/ja/docs/Web/API/Response
TypeScriptで型をつけてwrapする
FetchAPIはそのまま使うとanyを扱う必要があったり、クエリパラメータのエンコード機能がなかったりするので簡易的にWrapしたAPIClientを経由して利用します。
const API_ENDPOINT = 'https://exmaple.com' type Params = { [key: string]: string | number }; class ApiClient { get = async <T>(path: string, params: Params = {}): Promise<T> => { const url = this.createUrl(path, params); const response = await fetch(url); if (response.ok) { return (await response.json()) as T; } else { const status = response.status; const body = await response.text(); throw new Error(`status: ${status}, body: ${body}`); } }; private createUrl(path: string, params: Params = {}): string { let url: string; if (Object.keys(params).length == 0) { const encoded_params = this.encoded_params(params); url = `${API_ENDPOINT}/${path}?${encoded_params.join('&')}`; } else { url = `${API_ENDPOINT}/${path}`; } return url; } private encoded_params(params: Params): string[] { return Object.keys(params).map( key => `${encodeURIComponent(key)}=${encodeURIComponent(String(params[key]))}`, ); } } export default new ApiClient();
型を指定してGET
intreface Image { id: number; url: string; width: number; height: number; } const image = await = ApiClient.get<Image>(`images/${imageId}`); return image.url;
FlatList
FlatListとは
- ReactNative公式のリストを表示するのコンポーネント
- 多機能でかつインターフェースが扱いやすい
- FlatListのためにReactNativeが使いたくなるレベル
https://facebook.github.io/react-native/docs/flatlist
最小実装
<FlatList data={[{key: 'a'}, {key: 'b'}]} //データセットの提供 renderItem={({item}) => <Text>{item.key}</Text>} //描画方法の指定 />
APIからデータを受け取り表示
架空のAPIから過去のメッセージの一覧を取得する実装例です。ポイントは3点あります。
interface Props {} interface State { messages: Message[]; } interface Message { id: number; text: string; } class App extends React.Component<Props, State> { //コンポーネントが描画されるタイミングで呼ばれるイベント async componentDidMount() { const messages = await ApiClient.get<Message[]>('messages/1'); this.setState({ messages }); // コンポーネントの状態を差分更新 } render() { return ( <FlatList keyExtractor={item => { return String(item.id);}} data={this.state.messages} renderItem={({ item }: { item: Message }) => <Text>{item.text}</Text>} /> ); } }
FlatListの便利機能
ネイティブ実装だとかなり苦労するPull-to-Refreshや無限スクロールも数行で実装できます。今回は省略しますがヘッダー,フッター,複数カラムや横向きのスクロールなどで手軽に作成できます。
Pull-to-Refresh
<FlatList keyExtractor={item => { return String(item.id);}} data={this.state.messages} renderItem={({ item }: { item: Message }) => <Text>{item.text}</Text>} + onRefresh={() => { handleOnRefresh(); }} //再読込処理を呼び出す + refreshing={this.state.refreshing} //リフレッシュ処理が走っているか状態をセット />
無限スクロール
<FlatList
keyExtractor={item => { return String(item.id);}}
data={this.state.messages}
renderItem={({ item }: { item: Message }) => <Text>{item.text}</Text>}
+ onEndReached ={() => { handleonEndReached(); }} //次ページのデータを読み込む
/>