react-redux-firebase登录Promise在auth状态更新前resolve,引发路由渲染问题
解决登录后PrivateRoute未检测到Auth状态的问题
这个问题的核心原因很明确:你在firebase.login()的Promise回调里立即触发路由跳转时,react-redux-firebase还没把最新的认证状态同步到Redux Store,这时候PrivateRoute读取到的还是旧的无UID的auth数据,导致被重定向回登录页。而之后Store里的auth状态更新时,你的PrivateRoute又因为没有正确监听Store的变化,没能重新渲染并加载受保护页面。
下面是具体的修复步骤:
1. 让PrivateRoute从Redux Store获取Auth状态
你的PrivateRoute目前是直接从props.firebase.auth获取认证信息,但这个实例的状态变化不会触发组件重新渲染。正确的做法是从Redux Store读取同步后的auth状态,这样Store更新时组件会自动重新渲染。
修改你的PrivateRoute组件:
import { connect } from 'react-redux'; import { isLoaded, isEmpty } from 'react-redux-firebase'; import { Route, Redirect } from 'react-router-dom'; class PrivateRouteView extends Component { render() { const { key, auth, path, renderRoute } = this.props; return ( <Route exact key={key} path={path} render={(props) => { // 先等待auth状态加载完成,避免中间态判断错误 if (!isLoaded(auth)) { return <div>Loading...</div>; // 可以替换成你的加载组件 } // 已加载且存在有效认证信息,渲染受保护路由 if (!isEmpty(auth) && auth.uid) { return renderRoute(props); } // 否则重定向到登录页 return ( <Redirect to={{ pathname: '/login', state: { from: props.location } }} /> ); }} /> ); } } // 从Redux Store中获取同步后的firebase auth状态 const mapStateToProps = (state) => ({ auth: state.firebase.auth }); export default connect(mapStateToProps)(PrivateRouteView);
2. 调整登录逻辑,等待Auth状态同步后再跳转
不要再在firebase.login()的then回调里直接触发路由跳转,而是监听Redux Store中auth状态的变化,当检测到UID出现时再执行跳转。
修改你的登录容器组件逻辑:
import { connect } from 'react-redux'; import { isLoaded, isEmpty } from 'react-redux-firebase'; import { push } from 'react-router-redux'; import { reset } from 'redux-form'; import withFirebase from 'react-redux-firebase'; class LoginContainerView extends Component { componentDidUpdate(prevProps) { const { auth, pushToDashboard, resetLoginForm } = this.props; // 当auth状态加载完成、存在UID,且之前没有UID时,执行跳转和表单重置 if (isLoaded(auth) && !isEmpty(auth) && !prevProps.auth.uid) { pushToDashboard(); resetLoginForm(); } } render() { // 你的登录表单渲染代码,保持不变 return ( // ... 表单UI ); } } const mapStateToProps = (state) => ({ auth: state.firebase.auth }); const mapDispatchToProps = (dispatch) => ({ pushToDashboard: () => dispatch(push(ROUTE_OBJS.SECURED[ROUTES.DASHBOARD].path)), resetLoginForm: () => dispatch(reset(SINGLE_PAGE_FORMS.login)) }); // 调整高阶组件的包裹顺序和onSubmit逻辑 export default withFirebase(connect(mapStateToProps, mapDispatchToProps)(reduxForm({ form: SINGLE_PAGE_FORMS.login, onSubmit: (values, dispatch, props) => { const { firebase } = props; const { username: email, password } = values; return firebase.login({ email, password }) .then(() => { dispatch(openNotificationCenterAC({ message: 'Successfully logged in!', messageType: MESSAGE_TYPE_SUCCESS })); }) .catch((error) => { dispatch(openNotificationCenterAC({ message: error.message, messageType: MESSAGE_TYPE_ERROR })); }); } })(LoginContainerView)));
为什么这样能解决问题?
- PrivateRoute的响应性:现在PrivateRoute通过
connect订阅了Redux Store的变化,当react-redux-firebase把登录后的auth状态同步到Store时,组件会立即重新渲染,此时能正确读取到UID,加载受保护页面。 - 跳转时机正确:通过
componentDidUpdate监听auth状态的变化,确保只有当UID已经存在于Store中时才执行跳转,避免了过早跳转导致的重定向问题。
另外,确保你的react-redux-firebase配置正确(比如在Store初始化时已经添加了firebase reducer),这样auth状态才能正常同步到Redux中。
内容的提问来源于stack exchange,提问作者GoreDefex
相关产品推荐
相关产品推荐

