2016-01-20 52 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')。我有我的對話框能夠從任何頁面啓動,所以這很好用,只需要將它保存在路由中的一個地方。對不起,沒有什麼比你想要的更多幫助。 –