2016-01-20 26 views
1

我有react/redux/react-router应用与公共私人部分。 登录和注册表单显示为模式对话框,没有自己的路由。模态对话框权威性与反应路由器

所需流量: 用户点击链接- 成功的权威性过渡到链接的页面,否则用户离开当前页面上的情况下> - >模态对话框显示当前页面上。

如果没有当前页面显示的索引页,并继续与我试图存档此使用的OnEnter钩流动

,但据我可以看到在执行前的钩转变发生。如果我尝试使用history.goBack(),它会导致页面重新渲染并且看起来很脏。

有什么办法解决这个问题,没有不必要的重定向和额外的渲染调用?

回答

1

好的 - 我想我想出了一种处理这个问题的方法,它涵盖了所有的角落案例。它确实需要你有一些方法可以从几乎任何组件访问应用程序状态。我正在使用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在本地存储路由或其他)。此外,为了简洁,我省略了一些通过道具的中间组件。

其中一些可能是功能组件,但我将它们留下来以显示更多细节。通过对这些内容进行抽象还有一些改进的余地,但是我再次将它留给冗余以显示更多细节。希望这可以帮助!

+0

如果没有先前的路由,我忘记了关于索引的部分,但如果前面的路由为空/空,那只是推/替换中的一个IF。 –

+0

虽然提供了相当不错的流程来处理直接导航到私人页面,但它并没有帮助主要问题 - 在当前页面上显示模态窗口,而不是在目标页面上显示。 我正在寻找某种位置更改回调之前,但看起来像我只是需要延长链接标记 – ETK

+0

是的我想到了和删除onTransitionTo一样多,还没有找到更好的方式来处理它。这确实非常接近,因为如果它没有登录,它就隐藏了目标页面上的内容,除登录之外唯一的'out'取消 - 这些路由返回到它们来自的页面(或'home')。我有我的对话框能够从任何页面启动,所以这很好用,只需要将它保存在路由中的一个地方。对不起,没有什么比你想要的更多帮助。 –