最近一直在寫一個React、Redux的前端項目,登陸狀態驗證這一塊仍是比較頭疼的。前端
個人實踐下有三種方式來驗證用戶登陸狀態,目前我選擇用三種方式一塊兒用在項目裏面。json
Redux高階函數驗證(High-Order Function)函數
Actions中間件驗證性能
Component WillMount 驗證fetch
之因此用三種方式一塊兒是由於Redux高階函數在性能調優的時候並非特別容易。ui
//把須要登陸狀態驗證的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中:this
{ path:'courseCate',component:requireAuthentication(CourseCate)}
目前存在的一些問題:url
高階函數中傳入的最頂層的Component不能再使用connectspa
過多的高階函數生命週期的邏輯難以維護、性能隱患code
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))) } }
目前存在的一些問題:
雖然能夠避免過多的高階函數函數致使頁面性能降低,可是沒法很好知足業務邏輯
驗證若是未經過直接阻斷當前操做
這基本上能夠認爲是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驗證,使用範圍就比較狹窄了。
你們雨露均沾
以上是我我的目前的一些小看法,歡迎各位指正和補充哈。