Redux/Firebase - 在 state 中接收到 uid 后组件未更新
Redux/Firebase - Component not updating after uid is received in state
我正在为我的 Redux 应用程序使用 Firebase 的身份验证 API。我有一个应用程序组件,应该在收到用户的 UID 身份验证时收到通知,并切换向用户显示 header(登录 header 或注销 header)。但是,在用户已经登录并重新访问主路由的情况下,当 UID 存储到应用程序状态时,我似乎无法将我的主应用程序设置为 re-render。
大致流程是这样的:
In routes/index.js: Firebase 的 onAuthStateChanged 观察者
识别用户是否已经登录
路由负载。如果有用户,发送操作来复制他们的 UID
从 Firebase 到我们的州并将它们发送到 "connect" 页面。
In actions.jsx: startLoginForAuthorizedUser 操作创建者
调度一个动作以使用新的 UID & 更新 auth reducer
将用户重新路由到 "connect".
In reducers.jsx: "auth" 状态更新为包括用户的
UID 允许组件切换元素取决于
身份验证状态。
In App.jsx: 无论出于何种原因,mapStateToProps 未收到
更新状态,即使用户已通过身份验证并且 Redux dev
工具显示使用新 UID 更新的状态。
最终结果是经过身份验证的用户会按预期看到 "connect" 页面,但仍然会看到 logged-out header。这是代码:
App.jsx
import React from 'react';
import { connect } from 'react-redux';
import * as actions from 'actions';
import HeaderLoggedOut from './HeaderLoggedOut';
import ModalOverlay from './ModalOverlay';
import MenuWrapper from './MenuWrapper';
import Header from './Header';
import Tabs from './Tabs';
export const App = React.createClass({
render(){
const { uid } = this.props;
console.log("App.jsx: uid:", uid);
if(!uid){
return(
<div>
<HeaderLoggedOut />
<div className="tonal-main">
<div className="tonal-content">
{ this.props.children }
</div>
</div>
<ModalOverlay />
</div>
);
}
return(
<MenuWrapper>
<Header />
<div className="tonal-content">
{ this.props.children }
</div>
<Tabs />
</MenuWrapper>
);
}
});
const mapStateToProps = (state) => {
// state is not updated
return {
uid: state.auth.uid
};
};
export default connect(mapStateToProps)(App);
router/index.js
import App from 'App.jsx';
import Connect from 'connect/Connect.jsx';
import firebase from 'app/firebase';
const store = require('store').configure();
firebase.auth().onAuthStateChanged((user) => {
if(user.emailVerified && user.uid){
store.dispatch(actions.startLoginForAuthorizedUser(user.uid));
} else {
browserHistory.push('/');
}
});
const requireLogin = (nextState, replace, next) => {
const currentUser = firebase.auth().currentUser;
if(!currentUser){
replace('/');
}
next();
};
const redirectIfLoggedIn = (nextState, replace, next) => {
const currentUser = firebase.auth.currentUser;
if(currentUser){
replace('/connect');
}
next();
};
export default (
<Router history={ browserHistory }>
<Route path="/" component={ App }>
<IndexRoute component={ Landing } onEnter={ redirectIfLoggedIn } />
<Route path="connect" component = { Connect } onEnter = { requireLogin } />
</Route>
</Router>
);
Actions.jsx
// ...actions, imports, etc...
export var startLoginForAuthorizedUser = (uid) => {
return (dispatch) => {
dispatch(login(uid));
dispatch(pushToRoute('/connect'));
};
};
export var login = (uid) => {
console.log('actions: logging in user with uid ', uid);
return{
type: 'LOGIN',
uid
};
};
export var pushToRoute = (route) => {
browserHistory.push(route);
};
Reducer.jsx
const authInitialState = {
uid: ""
};
export const authReducer = (state = authInitialState, action) => {
switch(action.type){
case 'LOGIN':
return {
...state,
uid: action.uid
};
case 'LOGOUT':
return {
...state,
uid: ""
};
default:
return state;
}
};
非常感谢各位专家的帮助。这让我抓狂。
经过大量令人尴尬的反复试验后,我弄明白了。对于将来想要同时使用 react-router
/react-router-dom
和 firebase 的 onAuthStateChanged()
观察者的任何其他人,只要知道你必须保留观察者代码在最顶层的组件(在 ReactDOM.render()
中呈现提供程序的地方)。
如果您将它放在其他地方,它似乎无法正常工作,坦率地说,我不知道为什么。如果更熟悉 firebase 的人想解释那里发生了什么,以及为什么它可以在顶级组件中工作,但不能在路由索引文件中工作,我相信它会对以后的人有所帮助。
我正在为我的 Redux 应用程序使用 Firebase 的身份验证 API。我有一个应用程序组件,应该在收到用户的 UID 身份验证时收到通知,并切换向用户显示 header(登录 header 或注销 header)。但是,在用户已经登录并重新访问主路由的情况下,当 UID 存储到应用程序状态时,我似乎无法将我的主应用程序设置为 re-render。
大致流程是这样的:
In routes/index.js: Firebase 的 onAuthStateChanged 观察者 识别用户是否已经登录 路由负载。如果有用户,发送操作来复制他们的 UID 从 Firebase 到我们的州并将它们发送到 "connect" 页面。
In actions.jsx: startLoginForAuthorizedUser 操作创建者 调度一个动作以使用新的 UID & 更新 auth reducer 将用户重新路由到 "connect".
In reducers.jsx: "auth" 状态更新为包括用户的 UID 允许组件切换元素取决于 身份验证状态。
In App.jsx: 无论出于何种原因,mapStateToProps 未收到 更新状态,即使用户已通过身份验证并且 Redux dev 工具显示使用新 UID 更新的状态。
最终结果是经过身份验证的用户会按预期看到 "connect" 页面,但仍然会看到 logged-out header。这是代码:
App.jsx
import React from 'react';
import { connect } from 'react-redux';
import * as actions from 'actions';
import HeaderLoggedOut from './HeaderLoggedOut';
import ModalOverlay from './ModalOverlay';
import MenuWrapper from './MenuWrapper';
import Header from './Header';
import Tabs from './Tabs';
export const App = React.createClass({
render(){
const { uid } = this.props;
console.log("App.jsx: uid:", uid);
if(!uid){
return(
<div>
<HeaderLoggedOut />
<div className="tonal-main">
<div className="tonal-content">
{ this.props.children }
</div>
</div>
<ModalOverlay />
</div>
);
}
return(
<MenuWrapper>
<Header />
<div className="tonal-content">
{ this.props.children }
</div>
<Tabs />
</MenuWrapper>
);
}
});
const mapStateToProps = (state) => {
// state is not updated
return {
uid: state.auth.uid
};
};
export default connect(mapStateToProps)(App);
router/index.js
import App from 'App.jsx';
import Connect from 'connect/Connect.jsx';
import firebase from 'app/firebase';
const store = require('store').configure();
firebase.auth().onAuthStateChanged((user) => {
if(user.emailVerified && user.uid){
store.dispatch(actions.startLoginForAuthorizedUser(user.uid));
} else {
browserHistory.push('/');
}
});
const requireLogin = (nextState, replace, next) => {
const currentUser = firebase.auth().currentUser;
if(!currentUser){
replace('/');
}
next();
};
const redirectIfLoggedIn = (nextState, replace, next) => {
const currentUser = firebase.auth.currentUser;
if(currentUser){
replace('/connect');
}
next();
};
export default (
<Router history={ browserHistory }>
<Route path="/" component={ App }>
<IndexRoute component={ Landing } onEnter={ redirectIfLoggedIn } />
<Route path="connect" component = { Connect } onEnter = { requireLogin } />
</Route>
</Router>
);
Actions.jsx
// ...actions, imports, etc...
export var startLoginForAuthorizedUser = (uid) => {
return (dispatch) => {
dispatch(login(uid));
dispatch(pushToRoute('/connect'));
};
};
export var login = (uid) => {
console.log('actions: logging in user with uid ', uid);
return{
type: 'LOGIN',
uid
};
};
export var pushToRoute = (route) => {
browserHistory.push(route);
};
Reducer.jsx
const authInitialState = {
uid: ""
};
export const authReducer = (state = authInitialState, action) => {
switch(action.type){
case 'LOGIN':
return {
...state,
uid: action.uid
};
case 'LOGOUT':
return {
...state,
uid: ""
};
default:
return state;
}
};
非常感谢各位专家的帮助。这让我抓狂。
经过大量令人尴尬的反复试验后,我弄明白了。对于将来想要同时使用 react-router
/react-router-dom
和 firebase 的 onAuthStateChanged()
观察者的任何其他人,只要知道你必须保留观察者代码在最顶层的组件(在 ReactDOM.render()
中呈现提供程序的地方)。
如果您将它放在其他地方,它似乎无法正常工作,坦率地说,我不知道为什么。如果更熟悉 firebase 的人想解释那里发生了什么,以及为什么它可以在顶级组件中工作,但不能在路由索引文件中工作,我相信它会对以后的人有所帮助。