Only one API call when app just started

This commit is contained in:
Zhiyuan Zheng 2020-12-22 00:50:47 +01:00
parent 2bd9e6be2f
commit 436b0ab4dd
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
3 changed files with 98 additions and 36 deletions

87
App.tsx
View File

@ -1,5 +1,5 @@
import * as SplashScreen from 'expo-splash-screen'
import React, { useEffect, useState } from 'react'
import React, { useCallback, useEffect, useState } from 'react'
import { QueryClient, QueryClientProvider } from 'react-query'
import { Provider } from 'react-redux'
import { PersistGate } from 'redux-persist/integration/react'
@ -8,6 +8,7 @@ import { Index } from '@root/Index'
import { persistor, store } from '@root/store'
import ThemeManager from '@utils/styles/ThemeManager'
import { resetLocal, updateLocal } from '@root/utils/slices/instancesSlice'
import client from '@root/api/client'
const queryClient = new QueryClient()
@ -22,6 +23,8 @@ const queryClient = new QueryClient()
const App: React.FC = () => {
const [appLoaded, setAppLoaded] = useState(false)
const [startVerification, setStartVerification] = useState(false)
const [localCorrupt, setLocalCorrupt] = useState(false)
useEffect(() => {
const delaySplash = async () => {
try {
@ -45,38 +48,66 @@ const App: React.FC = () => {
}
}, [appLoaded])
const onBeforeLift = useCallback(() => setStartVerification(true), [])
useEffect(() => {
const verifyCredentials = async () => {
const localUrl = store.getState().instances.local.url
const localToken = store.getState().instances.local.token
if (localUrl && localToken) {
client({
method: 'get',
instance: 'remote',
instanceDomain: localUrl,
url: `accounts/verify_credentials`,
headers: { Authorization: `Bearer ${localToken}` }
})
.then(res => {
if (res.body.id !== store.getState().instances.local.account.id) {
store.dispatch(resetLocal())
setLocalCorrupt(true)
setAppLoaded(true)
}
})
.catch(() => {
store.dispatch(resetLocal())
setLocalCorrupt(true)
setAppLoaded(true)
})
} else {
setAppLoaded(true)
}
}
if (startVerification) {
verifyCredentials()
}
}, [startVerification])
const main = useCallback(
bootstrapped => {
if (bootstrapped && appLoaded) {
require('@root/i18n/i18n')
return (
<ThemeManager>
<Index localCorrupt={localCorrupt} />
</ThemeManager>
)
} else {
return null
}
},
[appLoaded]
)
return (
<QueryClientProvider client={queryClient}>
<Provider store={store}>
<PersistGate
persistor={persistor}
onBeforeLift={async () => {
const localUrl = store.getState().instances.local.url
const localToken = store.getState().instances.local.token
if (localUrl && localToken) {
const dispatchStatus = await store.dispatch(
updateLocal({ url: localUrl, token: localToken })
)
if (dispatchStatus.type.includes('/rejected')) {
store.dispatch(resetLocal())
}
}
setAppLoaded(true)
}}
>
{bootstrapped => {
if (bootstrapped) {
require('@root/i18n/i18n')
return (
<ThemeManager>
<Index />
</ThemeManager>
)
} else {
return null
}
}}
</PersistGate>
onBeforeLift={onBeforeLift}
children={main}
/>
</Provider>
</QueryClientProvider>
)

View File

@ -3,7 +3,7 @@ import { createBottomTabNavigator } from '@react-navigation/bottom-tabs'
import { NavigationContainer } from '@react-navigation/native'
import { enableScreens } from 'react-native-screens'
import React from 'react'
import React, { useEffect } from 'react'
import { StatusBar } from 'react-native'
import Toast from 'react-native-toast-message'
import { Feather } from '@expo/vector-icons'
@ -16,7 +16,7 @@ import ScreenMe from '@screens/Me'
import { themes } from '@utils/styles/themes'
import { useTheme } from '@utils/styles/ThemeManager'
import getCurrentTab from '@utils/getCurrentTab'
import { toastConfig } from '@components/toast'
import { toast, toastConfig } from '@components/toast'
import { useTranslation } from 'react-i18next'
import { useSelector } from 'react-redux'
import { getLocalUrl } from './utils/slices/instancesSlice'
@ -32,7 +32,11 @@ export type RootStackParamList = {
'Screen-Me': undefined
}
export const Index: React.FC = () => {
export interface Props {
localCorrupt: boolean
}
export const Index: React.FC<Props> = ({ localCorrupt }) => {
const localInstance = useSelector(getLocalUrl)
const { i18n } = useTranslation()
const { mode, theme } = useTheme()
@ -41,6 +45,18 @@ export const Index: React.FC = () => {
dark = 'light-content'
}
useEffect(() => {
const showLocalCorrect = localCorrupt
? toast({
type: 'error',
content: '登录已过期',
description: '请重新登录',
autoHide: false
})
: undefined
return showLocalCorrect
}, [localCorrupt])
return (
<>
<StatusBar barStyle={barStyle[mode]} />

View File

@ -63,13 +63,21 @@ const ToastBase = ({ config }: { config: Config }) => {
>
<View style={styles.container}>
<Feather
// @ts-ignore
name={iconSet[config.type]}
color={theme[config.type]}
size={StyleConstants.Font.Size.M + 2}
/>
<Text style={[styles.text, { color: theme.primary }]}>
{config.text1}
</Text>
<View style={styles.texts}>
<Text style={[styles.text1, { color: theme.primary }]}>
{config.text1}
</Text>
{config.text2 && (
<Text style={[styles.text2, { color: theme.secondary }]}>
{config.text2}
</Text>
)}
</View>
</View>
</SafeAreaView>
)
@ -91,11 +99,18 @@ const styles = StyleSheet.create({
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
padding: StyleConstants.Spacing.M
},
text: {
fontSize: StyleConstants.Font.Size.M,
texts: {
marginLeft: StyleConstants.Spacing.S
},
text1: {
fontSize: StyleConstants.Font.Size.M
},
text2: {
fontSize: StyleConstants.Font.Size.S,
marginTop: StyleConstants.Spacing.S
}
})