初めに
APIを実行している時、Loading画面を表示できたらアプリっぽくなりますね。
なのでLoadingコンポーネントを作ってそいつを表示してみましょう
ReactNativeで実装します
画面実装
こちらの記事を参考に実装していきます。
少し長くて申し訳ないのですが上からコピペしていくだけで全然OKです。
React NativeでNavigationを使っていい感じに画面遷移する
Reduxがムズイのでtoolkitでどうにか簡単に実装する
sliceの修正
まずはどちらか片方のsliceを修正します。
stateを追加して、API実行中と実行終了時にフラグを返します。
userSlice.js
import {createSlice} from '@reduxjs/toolkit';
const userInitialState = {
userName: null,
userEmail: null,
img: null,
// 新しいstateを定義、初期値はfalse
isLoading: false,
};
export const userSlice = createSlice({
name: 'user',
initialState: userInitialState,
reducers: {
getInfo: state => {
state.userName = 'Tanaka Taro';
state.userEmail = 'practice@example.com';
},
resetInfo: state => {
state.userName = userInitialState.userName;
state.userEmail = userInitialState.userEmail;
},
// 画像取得開始時
getImgStart: state => {
state.isLoading = true;
},
// 画像取得完了時
getImgSuccess: (state, {payload}) => {
state.isLoading = false;
state.img = payload;
},
},
});
export const {
getInfo,
resetInfo,
getImgStart,
getImgSuccess,
} = userSlice.actions;
getImageStartをした時にisLoadingをtrue
getImageSuccessの時にisLoadingをfalseにしてますね。
これによりLoadingコンポーネントを出し分けします(trueなら表示、falseなら表示しない方向で進めます)
sagaの名前を修正
getImgStartとgetImgSuccessにしたのでsagaの該当箇所を修正します
userSaga.js
import axios from 'axios';
import {put, call, takeLatest} from 'redux-saga/effects';
// 修正
import {getImgSuccess} from './userSlice';
function baseAxios() {
const url = 'https://dog.ceo/api/breeds/image/random';
return axios.get(url);
}
function* callApi() {
try {
const res = yield call(baseAxios);
// 修正
yield put(getImgSuccess(res));
} catch (error) {
console.log(error);
}
}
export const getDog = () => ({type: 'GET_DOG'});
export function* userSaga() {
yield takeLatest('GET_DOG', callApi);
}
コンポーネントの作成
簡単なLoadingコンポーネントを作成します。
まずはsrc配下にcomponentディレクトリを作成しましょう
さらにその中にLoading.jsとindex.jsを作成します
Loading.jsに関してはこんな感じで実装しました
コピペしてしまってOKです笑
Loading.js
import React from 'react';
import {StyleSheet, View, ActivityIndicator} from 'react-native';
const Loading = () => {
return (
<View style={styles.container}>
<ActivityIndicator size="large" color="salmon" />
</View>
);
};
export default Loading;
const styles = StyleSheet.create({
container: {
flex: 1,
alignContent: 'center',
justifyContent: 'center',
},
});
index.jsではLoadingコンポーネントをexportするだけです
(Loading以外にもコンポーネントが多くなった時のためにexport用のファイルを分けています)
index.js
import Loading from './Loading';
export {Loading};
画面で表示してみる
HomeScreen.js上でLoadingコンポーネントを表示してみます
HomeScreen.js
import React from 'react';
import {StyleSheet, View, Text, Button, Image} from 'react-native';
// sliceからgetImgStartを新たにimport
import {getInfo, resetInfo, getImgStart} from '../redux/user/userSlice';
import {getDog} from '../redux/user/userSaga';
import {useSelector, useDispatch} from 'react-redux';
import {Loading} from '../component/';
const HomeScreen = ({navigation}) => {
const dispatch = useDispatch();
const user = useSelector(state => state.user);
const dogImage = user.img?.data.message;
const getImg = () => {
// getImageStartでisLoadingをtrueにする
dispatch(getImgStart());
// 画像取得完了時にisLoadingはfalseになる
dispatch(getDog());
};
// isLoadingの値で画面を出し分ける
return user.isLoading ? (
<Loading />
) : (
<View style={styles.container}>
<Text>私の名前は{user.userName}</Text>
<Text>メールアドレスは{user.userEmail}</Text>
<Image
style={styles.img}
source={{
uri: dogImage,
}}
/>
<Button
title="セットする"
onPress={() => {
dispatch(getInfo());
}}
/>
<Button
title="リセットする"
onPress={() => {
dispatch(resetInfo());
}}
/>
<Button title="犬を取得" onPress={getImg} />
<Button
title="画面遷移する"
onPress={() => {
navigation.navigate('Detail');
}}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
input: {
width: '50%',
borderWidth: 1,
},
img: {
width: '75%',
height: '50%',
},
});
export default HomeScreen;
API通信中はこのようにLoading画面が表示されました。
画像データが取得されたらLoadingは消えて元の画面が表示されるはずです。
まとめ
- sliceにはAPI実行中、Loading画面を表示するためのstateを追加して各actionに処理を記載
- Loadingコンポーネントを作成する
- 画面ではAPIを実行した時にLoadingコンポーネントが表示されるように記述を追加
簡単にですがこれでLoading画面が表示されるかと思います!