認証で管理するStateの例
authSlice.ts
import { createSlice } from '@reduxjs/toolkit';
const authinInitialState = {
isLoanching: true,
isLoading: false,
error: null,
token: null,
};
export const authSlice = createSlice({
name: 'login',
initialState: authinInitialState,
reducers: {
loginStart: (state) => {
state.isLoading = true;
},
loginSuccess: (state, { payload }) => {
state.isLoanching = false;
state.isLoading = false;
state.error = null;
state.token = payload;
},
loginFailure: (state, { payload }) => {
state.isLoanching = false;
state.isLoading = false;
state.error = payload;
state.token = null;
},
logout: (state) => {
state.isLoading = false;
state.error = null;
state.token = null;
},
},
});
export const { loginStart, loginSuccess, loginFailure, logout } = authSlice.actions;
JWTを端末に保存するためのAsyncStrage
Installation | Async Storagehttps://react-native-async-storage.github.io
yarn add @react-native-async-storage/async-storage
JWTの保存、読み込み、削除など一通り用意しておき、認証時の処理に差し込む。services/deviceStrage.ts
import AsyncStorage from '@react-native-async-storage/async-storage';
const JWT_KEY = 'jwt_key';
export const deviceStorage = {
async saveItem(key: string, value: string) {
try {
await AsyncStorage.setItem(key, value);
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
},
async saveJWT(token: string) {
try {
await AsyncStorage.setItem(JWT_KEY, token);
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
},
async loadJWT() {
try {
const value = await AsyncStorage.getItem(JWT_KEY);
return value;
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
return error;
}
},
async deleteJWT() {
try {
await AsyncStorage.removeItem(JWT_KEY);
} catch (error) {
console.log('AsyncStorage Error: ' + error.message);
}
},
};
スプラッシュ画面がすぐに終了しないようにする
ライブラリを使用する
https://github.com/crazycodeboy/react-native-splash-screenreact-native-make/set-splash.md at master 揃 bamlab/react-native-makehttps://github.com
スプラッシュ画面は、JWTの読み込みが完了したタイミングで明示的に終了させる。
yarn add react-native-splash-screen
Android
ReactNative(0.63)以降は、自動でライブラリとリンクするので、特に設定は必要ない。
以下、onCreate
(アプリ起動時の処理)のみ追加する。
これによって、明示的に指示しない限りスプラッシュスクリーンが終了しなくなる。
package com.myapp;
import com.facebook.react.ReactActivity;
追加
++ import android.os.Bundle;
++ import org.devio.rn.splashscreen.SplashScreen;
public class MainActivity extends ReactActivity {
追加
++ @Override
++ protected void onCreate(Bundle savedInstanceState) {
++ SplashScreen.show(this);
++ super.onCreate(savedInstanceState);
++ }
@Override
protected String getMainComponentName() {
return "myApp";
}
}
iOS
同じく起動時の処理に追加する。
これによって、明示的に指示しない限りスプラッシュスクリーンが終了しなくなる。
#import "AppDelegate.h"
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
追加
++ #import "RNSplashScreen.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// ...other code
[self.window makeKeyAndVisible];
追加
++ [RNSplashScreen show];
return YES;
}
@end
Splashコンポーネントの作成
Splashコンポーネントといっても、画面には何も表示する必要はなく、
JWTの読み込みや、アプリ起動時に必要な処理を行う。
また、処理が終了した際にスプラッシュを非表示にする。
SplashScreen.tsx
import { useEffect } from 'react';
import { useDispatch } from 'react-redux';
import SplashScreen from 'react-native-splash-screen';
import { deviceStorage } from 'src/services/deviceStrage';
export default function () {
const dispatch = useDispatch();
useEffect(() => {
deviceStorage
.loadJWT()
.then((jwt) => {
dispatch(loginSuccess(jwt)); // isLoanchingをfalseにする
})
.catch((error) => {
dispatch(loginFailure(error)); // isLoanchingをfalseにする
})
.finally(() => {
SplashScreen.hide(); //
});
}, [dispatch]);
return null;
}
React Navigation の設定
Page Not Found | React Navigation
アプリ起動時、未ログイン(JWTなし)、ログイン後(JWTあり)の画面を出し分ける。
例はReduxでTokenを管理している場合。
navigation.tsx
export const RootNavigator = () => {
const { isLoanching, token } = useSelector((state: RootState) => state.auth);
if (isLoanching) return <SplashScreen />;
return (
<NavigationContainer>
<RootStack.Navigator headerMode="none">
{!token ? (
<>
<RootStack.Screen name="SignIn" component={SignInScreen} />
<RootStack.Screen name="SignUp" component={SignUpScreen} />
</>
) : (
<>
<RootStack.Screen name="AppBottomTab" component={AppBottomTabNavigator} />
<RootStack.Screen name="ChatRooms" component={ChatRoomScreen} />
</>
)}
</RootStack.Navigator>
</NavigationContainer>
);
};