最近一直在寫一個React、Redux的前端專案,登入狀態驗證這一塊還是比較頭疼的。
我的實踐下有三種方式來驗證使用者登入狀態,目前我選擇用三種方式一起用在專案裡面。
-
Redux高階函式驗證(High-Order Function)
-
Actions中介軟體驗證
-
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)))
}
}
目前存在的一些問題:
-
雖然可以避免過多的高階函式函式導致頁面效能下降,但是無法很好滿足業務邏輯
-
驗證如果未通過直接阻斷當前操作
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驗證,使用範圍就比較狹窄了。
大家雨露均沾
以上是我個人目前的一些小見解,歡迎各位指正和補充哈。