高階組件是什麼?乍一聽,感受是個很高級的概念,可是不要被這個名詞嚇到,說簡單點 就是給已有的一個組件外面「包一層」。 咱們知道 「高階函數」 是傳入函數做爲參數, 高階組件 其實就是傳入 組件做爲參數,並返回一個新組件。html
高階組件的做用是什麼?項目開發當中,一般咱們會把一些公用的邏輯抽離出來, 而且應用到不少組件上,給組件賦予一個新的能力,這時候就須要用到它。前端
props
時簡而言之,若是你須要給不少組件都寫相同的判斷邏輯,那麼能夠考慮提取出一個高階組件vue
記得之前開發vue 項目的時候也遇到過相似的問題,那時用的vue-router,實現方式是在全局的
router.beforeEach
方法中獲取用戶信息,根據用戶的角色和權限跳轉到不一樣的頁面。參考官方文檔react
一個實現路由權限控制的高階組件:git
const LodingUserTip = () => {
return (
<p>
<Icon type="loading-3-quarters" />
正在獲取用戶信息,稍後...
</p>
)
}
const UnAuthoriedTip = () => {
return (
<p>
<Icon type="lock" />
<h5 style={{color: 'red'}}>抱歉,您沒有訪問該頁面的權限...</h5>
</p>
)
}
const authDecorator = WrappedComponent => {
// auth 組件是最終返回的高階組件
const Auth = props => {
const {
match: {path, params},
currentUser: {role_type: roleType},
userLoading,
history,
location,
} = props
const {match} = props
// 用戶信息正在加載
if (userLoading) {
return <LodingUserTip />
}
// 當前登陸用戶沒有訪問權限
if (!roles.includes(roleType)) {
return <UnAuthoriedTip />
}
// 若是沒有找到對應頁面,則跳轉至該權限對應的默認頁面
const {allowedUrl, defaultUrl} = AUTH_MAP[roleType]
if (!allowedUrl.includes(path)) {
history.push(defaultUrl)
return null
}
// 還能夠把額外的 props傳遞給你使用的組件
return (
<WrappedComponent
params={params}
match={match}
location={location}
history={history}
roleType={roleType}
{...props}
/>
)
}
const mapStateToProps = ({
users,
loading: {models: {users: userLoading}},
}) => {
return {
currentUser: users.currentUser,
userLoading,
}
}
return withRouter(connect(mapStateToProps)(Auth))
}
export default authDecorator
複製代碼
上面這段代碼即是一個高階組件, 一般咱們會請求後端接口返回給咱們一個當前用戶的roleType
, 咱們在前端會存一個map,根據不一樣的roleType
映射到的不一樣的路由, map結構以下:github
export const AUTH_MAP = {
admin: {
allowedUrl: [
'/a/b',
],
defaultUrl: '/f',
},
superAdmin: {
allowedUrl: [
'/a/b',
'/c/d',
],
defaultUrl: '/e',
}
}
複製代碼
使用的時候能夠配合裝飾器,更簡單方便:vue-router
@authDecorator
class PageOneComponent extends React.Component {
...
複製代碼
高階組件中會判斷 當前的用戶角色與當前的路由是否匹配,若匹配不成功則顯示默認信息,或者跳轉到默認url(或者登錄頁)redux
在使用antd的Form.create(onFieldsChange:(props, fields) => {})
我很疑惑這裏 onFieldsChange 爲何能獲取到組件的props, 最後明白: 其實Form.create()返回了一個高階組件,會接收到全部傳給組件的props, 當fields變化的時候,antd執行onFieldsChange並把props傳進去即可以。segmentfault
但有一個要注意,若是一個組件有多個裝飾器(須要被多個高階組件包裹),須要注意順序,好比下面這個圖片,我但願在onFieldsChange 中獲取 從 redux 拿到的 dictionary
信息,這樣是獲取不到的,由於 最早執行的connect, 而後才執行的 Form.create()方法,Form.create()返回的高階組件只能獲取到以後傳遞給組件的props. 後端
如圖,debugger打斷點 看到 props中 沒有 dictionary
要想拿到全部的props,請按照下圖這樣作:(最早執行的是Form.create()返回的函數,因此後面執行的函數以及傳遞的props都會被onFieldsChange
接收到):
MyHOC.staticMethod = WrappedComponent.staticMethod
這樣明確的將靜態方法傳遞給高階組件,可是這樣太不嚴謹了,很容易漏掉。官方推薦的最佳實踐是使用 hoist-non-react-statics 第三方庫 自動copy 靜態方法hcysun.me/2018/01/05/… segmentfault.com/a/119000000… segmentfault.com/a/119000000… www.zhihu.com/question/58… hacpai.com/article/151…