我制作了一个使用firebase
电子邮件/通行证身份验证的应用程序,并使用redux-toolkit
管理状态,一切都很好,除了糟糕的用户体验,也就是说,当应用程序打开时,需要一秒钟来确定用户是否登录,因此,我在redux中有一个加载状态,也很好,但在初始加载期间,我可以先看到我的LoginScreen显示,然后在一两秒钟后,如果用户以前登录过,它会显示我的HomeScreen,所以我需要提供一个LoadingScreen来隐藏这种转换,并且在每次加载操作完成时只显示一个特定的屏幕。
我尝试添加一个本地状态,并在onAuthStateChange
函数内完成所有操作时将其设置为false,但它不起作用。
我的问题视频:https://drive.google.com/file/d/1a8Bu1bTqAANsWKDs0e5bjqVdZJWJRcMv/view?usp=sharing
请查看录音(上面的链接),以便您正确理解情况
下面是我的代码、入口文件和redux工具包状态文件:
条目文件:
const EntryPoint = () => {
const dispatch = useDispatch();
const user = useSelector(state => state.auth.user);
const authloading = useSelector(state => state.auth.loading);
useEffect(() => {
onAuthStateChanged(auth, result => {
if (result) {
const path = doc(db, 'users', result.uid);
getDoc(path)
.then(result => {
if (result.exists()) {
const data = result.data();
dispatch(
login({
displayName: data['displayName'],
email: data['email'],
photoURL: data['photoURL'],
phone: data['phone'],
}),
);
}
})
.catch(error => console.log('sign in error: ', error));
} else {
dispatch(logout());
}
dispatch(loading(false));
});
}, []);
if (authloading) return <Loader />;
return (
<Stack.Navigator>
{user ? <Stack.Screen name="Home" component={Home} /> : <Stack.Screen name="SignIn" component={SignIn} />}
</Stack.Navigator>
);
};
Redux状态:
import { createSlice } from "@reduxjs/toolkit";
const initialState = {
user: null,
loading: true,
}
export const authSlice = createSlice({
name: 'auth',
initialState,
reducers: {
login: (state, action) => {
state.user = action.payload;
},
logout: (state) => {
state.user = null;
},
loading: (state, action) => {
state.loading = action.payload;
},
}
});
我认为之所以会发生这种情况,是因为您在设置user
之前设置了loading = false
,这一点非常清楚,因为user
将在getDoc
调用之后设置(这会产生1秒或2秒的"坏用户体验")。
Reduxdispatch
返回一个Promise,因此您可以在设置用户后使用该Promise将loading
设置为false:
const EntryPoint = () => {
const dispatch = useDispatch();
const user = useSelector(state => state.auth.user);
const authloading = useSelector(state => state.auth.loading);
useEffect(() => {
onAuthStateChanged(auth, result => {
if (result) {
const path = doc(db, 'users', result.uid);
getDoc(path)
.then(result => {
if (result.exists()) {
const data = result.data();
dispatch(
login({
displayName: data['displayName'],
email: data['email'],
photoURL: data['photoURL'],
phone: data['phone'],
}),
)
.then(result => { dispatch(loading(false)); }); //<-- after user is setted, remove loading
}
else dispatch(loading(false)); //<-- if result does not exixsts, remove loading
})
.catch(error => {
dispatch(loading(false)); //<-- in case of error, remove loading
console.log('sign in error: ', error);
});
} else {
dispatch(logout())
.then(result => { dispatch(loading(false)); }); //<-- after logout, remove loading
}
});
}, []);
if (authloading) return <Loader />;
return (
<Stack.Navigator>
{user ? <Stack.Screen name="Home" component={Home} /> : <Stack.Screen name="SignIn" component={SignIn} />}
</Stack.Navigator>
);
};
通过这种方式,您可以100%确定只有在设置了用户之后,加载才会设置为false(避免糟糕的用户体验)。