Redux 登入狀態判斷的一些實踐

Weny發表於2016-07-15

最近一直在寫一個React、Redux的前端專案,登入狀態驗證這一塊還是比較頭疼的。

我的實踐下有三種方式來驗證使用者登入狀態,目前我選擇用三種方式一起用在專案裡面。

  1. Redux高階函式驗證(High-Order Function)

  2. Actions中介軟體驗證

  3. Component WillMount 驗證

之所以用三種方式一起是因為Redux高階函式在效能調優的時候並不是特別容易。

Redux高階函式驗證

//把需要登入狀態驗證的Component傳入到這個高階函式中
export function requireAuthentication(Component) {
    class AuthenticatedComponent extends Component {
        constructor(props) {
            super(props)
        }
        //只在首次Mount時來驗證許可權
        componentWillMount() {
            this.checkAuth();
        }
        checkAuth(){
            const {path,isSignIn,dispatch}=this.props;
            if(!isSignIn){
                //沒有登入
                //記錄當前頁面path
                //跳轉到SignIn Page處理登入 登入完成夠會跳回當前頁面
                dispatch(CommonActions.setNextUrl(path))
                browserHistory.push(`/sign`);
            }
        }
        render() {
            console.log(`auth render`)
            return (
                <div>
                
                    {this.props.isSignIn == true
                        ? <Component  {...this.props}/>
                        : null
                    }
                </div>
            )

        }
    }

    const mapStateToProps = (state) => ({
        path:state.routing.locationBeforeTransitions.pathname,
        isSignIn:state.common.isSignIn,
        state:state
    })
    return connect(mapStateToProps)(AuthenticatedComponent);
}

你可以把它像這樣用在router中:

{ path:`courseCate`,component:requireAuthentication(CourseCate)}

目前存在的一些問題:

  • 高階函式中傳入的最頂層的Component不能再使用connect

  • 過多的高階函式生命週期的邏輯難以維護、效能隱患

Actions中介軟體驗證

export function checkAuth(nextUrl,nextFn) {
    return (dispatch,getState)=>{
        //檢測使用者登入情況
        if(!getState().common.isSignIn){
            //沒有登入 記錄當前path 
            //跳轉到sign page 登入完成後 跳轉回來
            dispatch(setNextUrl(nextUrl));
            pushUrl(`/sign`);//封裝了 browserHistory.push(url)
        }else{
            //通過驗證後 執行下一個Fn
            dispatch(nextFn);
        }
    }
}

你可以像這樣用在你的Actions中

export function fetchFoo(url,conf) {

    return (dispatch,getState) => {
        if(shouldFetchFoo(getState())){
            dispatch(requestFetchFoo());
            return fetch(url,conf)
            .then(res=>res.json())
            .then(json=>{
                ...
            })
        }
    }
    
}
export function needFetchFoo(nextUrl,url,conf){
    retrun (dispatch)=>{
        dispatch(checkAuth(nextUrl,fetchFoo(url,conf)))
    }
}

目前存在的一些問題:

  1. 雖然可以避免過多的高階函式函式導致頁面效能下降,但是無法很好滿足業務邏輯

  2. 驗證如果未通過直接阻斷當前操作

Component WillMount 驗證

這基本上可以認為是Actions中間驗證的一種變種

export function checkAuthWithoutNextFn(nextUrl) {
    return (dispatch,getState)=>{
        //check if user sign in
        if(!getState().common.isSignIn){
            //if not set the nexturl 
            //and push url to sign page
            dispatch(setNextUrl(nextUrl));
            pushUrl(`/sign`);
        }
    }
}

你可以像這樣把他用在Component WillMount事件中

    componentWillMount(){
        const {dispatch} = this.props;
        dispatch(CommonActions.checkAuthWithoutNextFn(`/coursecate`));
    }

目前存在的一些問題:

  • 許可權未得到驗證時,不會阻斷子控制元件渲染,觸發子控制元件生命週期中的事件

舉個例子:
比如父控制元件中componetWillDidMount中呼叫該方法判斷使用者登入狀態
fatherComponet.js

    componentWillMount(){
        const {dispatch} = this.props;
        dispatch(CommonActions.checkAuthWithoutNextFn(`/coursecate`));
    }

然而子控制元件componentWillMount中有一個fetch是需要許可權驗證(此時父控制元件中並沒有阻斷子控制元件渲染,在父控制元件正在驗證許可權的同時,子控制元件的fetch執行了。高階函式可以阻斷子控制元件渲染)的。
雖然渲染順序是fatherComponet->childComponet
但是childComponet裡的componentWillMount也是觸發了(也就是說,在未驗證登入情況下就觸發了fetch),可能會造成一些不必要的請求
我目前的處理方式:在子控制元件ComponentWillMount的fetch中加入一個shouldFetch()進行請求前判斷

總結

1.高階函式適合用在:子控制元件需要確定許可權後渲染
2.actions中介軟體適合:無狀態頁面中的登入狀態判斷
3.component驗證,使用範圍就比較狹窄了。

大家雨露均沾

以上是我個人目前的一些小見解,歡迎各位指正和補充哈。

相關文章