好的 - 我想我想出了一种处理这个问题的方法,它涵盖了所有的角落案例。它确实需要你有一些方法可以从几乎任何组件访问应用程序状态。我正在使用Redux。这也假设登录,注册等没有路线。
我所做的是创建两个'包装'组件。第一个包裹任何不安全的路线和位置存储到一个状态值,使我们总是到最后不安全的路线参考...
import { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { setRoute } from './redux/client/ducks/auth';
function mapDispatchToProps(dispatch) {
return {
setRoute: bindActionCreators(setRoute, dispatch)
};
}
@connect(null, mapDispatchToProps)
export default class InsecureWrapper extends Component {
componentDidMount() {
const { location, setRoute } = this.props;
setRoute(location.pathname);
}
render() {
return (
<div>
{this.props.children}
</div>
)
}
}
另一种包装所有的安全路线。它显示登录对话框(也可以来回切换之间登录和注册或其他),并防止内容被显示,除非登录到应用程序...
import { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as authActions from './redux/client/ducks/auth';
function mapStateToProps(state) {
return {
auth: state.auth
};
}
function mapDispatchToProps(dispatch) {
return {
authActions: bindActionCreators(authActions, dispatch)
};
}
@connect(
mapStateToProps,
mapDispatchToProps
)
export default class SecureWrapper extends Component {
componentDidMount() {
const { auth, authActions } = this.props;
//see if user and if not prompt for login
if(!auth.loggedIn) {
authActions.openLogin();
}
}
//close any open dialogs in case the user hit browser back or whatever
componentWillUnmount() {
const { authActions } = this.props;
authActions.resetAuthDialogs();
}
render() {
const { auth, children } = this.props;
return (
<div className="container">
{auth.loggedIn &&
{children} ||
<span>YOU MUST BE LOGGED IN TO VIEW THIS AREA!</span>
}
</div>
);
}
}
在路线
然后,就包起来该包装需要...
import App from './containers/App';
import Dashboard from './containers/Dashboard';
import Secure from './containers/Secure';
import AuthWrapper from './common/client/components/AuthWrapper';
import InsecureWrapper from './common/client/components/InsecureWrapper';
export default [
{path: '/', component: App, //common header or whatever can go here
childRoutes: [
{component: InsecureWrapper,
childRoutes: [ //<- ***INSECURE ROUTES ARE CHILDREN HERE***
{path: 'dashboard', component: Dashboard}
]
},
{component: SecureWrapper,
//***SECURE ROUTES ARE CHILDREN HERE***
childRoutes: [
{path: 'secure', component:Secure}
]
}
]}
]
最后但并非最不重要......在你的对话框,你需要处理通过推动(或更换)的位置,以保存状态值取消。当然在成功登录,只需关闭它们...
import { Component } from 'react';
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import * as authActions from './redux/client/ducks/auth';
import LoginDialog from './common/client/components/dialogs/LoginDialog';
import RegisterDialog from './common/client/components/dialogs/RegisterDialog';
// this could also be replacePath if you wanted to overwrite the history
import { pushPath } from 'redux-simple-router';
function mapStateToProps(state) {
return {
auth: state.auth
};
}
function mapDispatchToProps(dispatch) {
return {
authActions: bindActionCreators(authActions, dispatch),
pushPath: bindActionCreators(pushPath, dispatch),
};
}
@connect(
mapStateToProps,
mapDispatchToProps
)
export default class AuthContainer extends Component {
_handleLoginCancel = (e) => {
const { auth, authActions, pushPath } = this.props;
pushPath(auth.prevRoute); // from our saved state value
authActions.closeLogin();
};
_handleLoginSubmit = (e) => {
const { authActions } = this.props;
// do whatever you need to login here
authActions.closeLogin();
};
render() {
const { auth } = this.props;
return (
<div>
<LoginDialog
open={auth.showLogin}
handleCancel={this._handleLoginCancel}
handleSubmit={this._handleLoginSubmit}
submitLabel="Login"
/>
...
</div>
)
}
}
我明明用ES6,巴贝尔和的WebPack ......但原则应不应该使用Redux的申请没有他们(你可以存储prev在本地存储路由或其他)。此外,为了简洁,我省略了一些通过道具的中间组件。
其中一些可能是功能组件,但我将它们留下来以显示更多细节。通过对这些内容进行抽象还有一些改进的余地,但是我再次将它留给冗余以显示更多细节。希望这可以帮助!
如果没有先前的路由,我忘记了关于索引的部分,但如果前面的路由为空/空,那只是推/替换中的一个IF。 –
虽然提供了相当不错的流程来处理直接导航到私人页面,但它并没有帮助主要问题 - 在当前页面上显示模态窗口,而不是在目标页面上显示。 我正在寻找某种位置更改回调之前,但看起来像我只是需要延长链接标记 – ETK
是的我想到了和删除onTransitionTo一样多,还没有找到更好的方式来处理它。这确实非常接近,因为如果它没有登录,它就隐藏了目标页面上的内容,除登录之外唯一的'out'取消 - 这些路由返回到它们来自的页面(或'home')。我有我的对话框能够从任何页面启动,所以这很好用,只需要将它保存在路由中的一个地方。对不起,没有什么比你想要的更多帮助。 –