ToDo一覧取得中の表示
REST APIを呼びだすと応答を受け取るまでに少し時間がかかります。呼びだし中に何もフィードバックを返さないと、アプリで処理中なのか、自分の操作が伝わっていないのか、ユーザには判断できなくなってしまいます。 そのため、REST APIの呼びだしのような時間のかかる非同期処理は、アプリが処理中であることをユーザに伝えるのが望ましいです。
また、ToDo一覧が最新化されていないため、削除されているToDoを更新してしまうようなことを防ぐようなケースを想定すると、処理が完了するまでブロックしたい操作もあります。
ToDoアプリでは、一覧の取得中はToDo一覧上にローディング中であることを伝えるアクティビティインジケータを表示しToDoの操作をブロックしましょう。
そのような機能を実現するためには処理中かどうかという状態を管理して、処理中の場合だけアクティビティインジケータとブロックするためのViewを表示します。
下のイメージはアクティビティインジケータを表示している画面です。
REST APIの呼びだし状態の管理
まず、REST APIを呼びだすコンポーネントで、REST APIを呼びだし中かどうかの状態を管理します。
次のように useState
を利用してloading
状態を管理します。
REST APIを呼びだすTodoService.getTodos()
の前でloading
中に設定し、finally
でloading
を解除します。
export const TodoBoard: React.FC = () => {
const navigation = useNavigation();
const {theme} = useContext(ThemeContext);
const [todos, setTodos] = useState<Todo[]>([]);
const [filterType, setFilterType] = useState<FilterType>(FilterType.ALL);
+ const [loading, setLoading] = useState(false);
useFocusEffect(
useCallback(() => {
let isActive = true;
+ setLoading(true);
TodoService.getTodos()
.then(response => {
if (isActive) {
setTodos(response);
}
})
- .catch(() => {});
+ .catch(error => {
+ console.log(error);
+ })
+ .finally(() => {
+ if (isActive) {
+ setLoading(false);
+ }
+ });
return () => {
isActive = false;
};
}, []),
エラー発生時の処理は実装しませんが、実装中にどのようなエラーが発生しているかを確認したいことは多いのでログ出力だけしています。
本来は、エラーが発生した場合にはユーザにもエラーの内容と(可能であれば)エラーから回復する方法を伝えるべきです。
処理中のUI表示
次に、処理中であることを表示するように修正します。
処理中はToDo一覧の上にアクティビティインジケータを表示し、ToDo一覧に表示されているToDoをユーザが操作できないようにします。 ただし、設定タブから設定画面を表示できるようにしておきます。
具体的にはloading
がtrue
の時だけアクティビティインジケータを中央に表示し、操作できないようにView
でToDo一覧を覆います。
操作をブロックするためのスタイル定義
まず、操作をブロックするためのindicatorContainer
とアクティビティインジケータを中央に表示するためのindicator
のスタイルを定義してください。
const styles = StyleSheet.create({
container: {
flex: 1,
},
/* ~省略~ */
iconContainerStyle: {
position: 'absolute',
bottom: 10,
right: 10,
},
+ indicatorContainer: {
+ position: 'absolute',
+ zIndex: 2,
+ width: '100%',
+ flex: 1,
+ alignContent: 'center',
+ height: '100%',
+ backgroundColor: 'rgba(0, 0, 0, 0.2)',
+ },
+ indicator: {
+ flex: 1,
+ },
});
処理中であることを伝えるUI
次にReact Nativeの ActivityIndicator
を表示します。
操作をブロックするためのContainerは、loading
中でなければ表示されないようにします。
import React, {useCallback, useContext, useState} from 'react';
-import {Alert, StyleSheet, View} from 'react-native';
+import {Alert, StyleSheet, View, ActivityIndicator} from 'react-native';
import {Icon, ThemeContext} from 'react-native-elements';
/* ~省略~ */
<Icon
name="plus"
type="font-awesome-5"
color={theme.colors?.primary}
reverse
size={30}
containerStyle={styles.iconContainerStyle}
onPress={() => {
navigation.navigate('TodoForm');
}}
/>
+ {loading && (
+ <View style={styles.indicatorContainer}>
+ <ActivityIndicator color="red" style={styles.indicator} size="large" />
+ </View>
+ )}
</View>
);
このままだとREST APIからの応答が早いため一瞬しかアクティビティインジケータが表示されないので、確認ができません。
TodoService.getTodos()
のfinally
でのsetLoaing(false)
をコメントアウトするとアクティビティインジケータを確認できますが、コードを修正しないとToDo一覧を操作できません。
次の動作確認でREST APIの応答を一定時間待つという状態を擬似的に作り出してみましょう。
動作確認
これで、ToDo一覧取得のREST APIを呼びだしている間はアクティビティインジケータが表示され、一部の操作はブロックされるようになりました。
REST APIからの応答が早く、アクティビティインジケータの確認が難しいのでREST APIを呼び出したら応答までの時間を待つことを擬似的に再現してみましょう。 応答時間を待つ処理はREST APIではなくREST APIクライアントで実装します。
REST APIクライントの接続先を切り替えていたconfig.ts
でMiddleware
というインタフェースを利用して機能を追加してみましょう。
Middlewareを利用して一定時間待機させるために、config.tsを次のように修正してください。
${IP}
はご自身の環境に合わせて設定したままにしてください。
Middlewareとは、特定の処理に対して共通的に行いたい処理(例えば、ログ記録、クラッシュレポート等)をカスタマイズして設定できるインタフェースです。
今回は、REST APIの応答時間を任意のものへ設定するのに使用してます。
import {Configuration, Middleware} from './generated-rest-client';
const waitResponse: Middleware = {
post: async context => {
await new Promise(resolve => setTimeout(resolve, 3000));
return Promise.resolve(context.response);
},
};
export const config = new Configuration({basePath: 'http://${IP}:9080/api', middleware: [waitResponse]});
ここまででREST APIを呼び出してから応答までの時間を擬似的に待つ設定が完了です。
ここからはアクティビティインジケータの表示と一部操作がブロックされていることの確認です。次の手順で確認してください。
- APIサーバを起動
- アプリを起動
- ログイン
ToDo一覧画面マウント時にToDo一覧取得APIを呼び出しています。その呼び出し中は画面中央にアクティビティインジケータが表示され、ToDo一覧に対する操作がブロックされていることが確認できます。