一、概念
把一个组件当成另外一个组件的参数传入,然后通过一定的判断,返回新的组件。
二、基本用法
三、实战
例1:监听鼠标位置
App.js
import React from 'react'
import HOCDemo from './6.高级特性/4.HOCDemo'
function App() {
return (
<div>
<HOCDemo a='999' />
</div>
)
}
export default App
4.HOCDemo.js
import React from 'react'
// 高阶组件
const withMouse = (Component) => {
class withMouseComponent extends React.Component {
constructor(props) {
super(props)
this.state = {
x: 0, y: 0 }
}
handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
})
}
render() {
return (
<div style={
{
height: '500px', background: 'pink' }} onMouseMove={
this.handleMouseMove}>
{
/* 1. 透传所有 props (vue使用$props v-bind) 2. 增加 mouse 属性 */}
<Component {
...this.props} mouse={
this.state}/>
</div>
)
}
}
return withMouseComponent
}
const App = (props) => {
const a = props.a // 999
const {
x, y } = props.mouse // 接收 mouse 属性
return (
<div style={
{
height: '500px' }}>
<h1>The mouse position is ({
x}, {
y})</h1>
<p>{
a}</p>
</div>
)
}
export default withMouse(App) // 返回高阶函数
例2:路由鉴权
App.js
// 导入路由
import {
unstable_HistoryRouter as HistoryRouter, Routes, Route } from 'react-router-dom'
import {
history } from './utils/history'
import './App.css'
import AuthRoute from './components/AuthRoute'
// 导入页面组件
// import Login from './pages/Login'
// import SysLayout from '@/pages/Layout'
// import Home from './pages/Home'
// import Article from './pages/Article'
// import Publish from './pages/Publish'
// 导入必要组件
import {
lazy, Suspense } from 'react'
// 按需导入路由组件
const Login = lazy(() => import('./pages/Login'))
const SysLayout = lazy(() => import('@/pages/Layout'))
const Home = lazy(() => import('./pages/Home'))
const Article = lazy(() => import('./pages/Article'))
const Publish = lazy(() => import('./pages/Publish'))
// 配置路由规则
function App() {
return (
<HistoryRouter history={
history}>
<Suspense
fallback={
<div
style={
{
textAlign: 'center',
marginTop: 200
}}
>
loading...
</div>
}
>
<div className="App">
<Routes>
{
/* 需要鉴权的路由 */}
<Route
path="/"
element={
<AuthRoute> // 高阶组件在这!!!!!!
<SysLayout/>
</AuthRoute>
}
>
<Route index element={
<Home />}/>
<Route path="/article" element={
<Article />} />
<Route path="/publish" element={
<Publish />} />
</Route>
{
/* 不需要鉴权的路由 */}
<Route path="/login" element={
<Login/>} />
</Routes>
</div>
</Suspense>
</HistoryRouter>
)
}
export default App;
AuthRoute.js
// 1. 判断token是否存在
// 2. 如果存在 直接正常渲染
// 3. 如果不存在 重定向到登录路由
// 高阶组件: 把一个组件当成另外一个组件的参数传入 然后通过一定的判断 返回新的组件
import {
getToken } from '@/utils'
import {
Navigate } from 'react-router-dom'
function AuthRoute ({
children }) {
const isToken = getToken()
if (isToken) {
return <>{
children}</>
} else {
return <Navigate to="/login" replace />
}
}
export default AuthRoute
// <AuthComponent> <Layout/> </AuthComponent>
// 登录:<><Layout/></>
// 非登录:<Navigate to="/login" replace />
具体请看我的项目
项目地址
四、Vue如何实现高阶组件???
混入(mixin)
函数化组件(functional component)等方式
1、mixin
// hocMixin.js
export const hocMixin = {
methods: {
logMessage(message) {
console.log(`HOC Log: ${
message}`);
},
},
};
// YourComponent.vue
<template>
<div>
<button @click="logMessage('Button Clicked')">Click me</button>
</div>
</template>
<script>
import {
hocMixin } from './hocMixin';
export default {
mixins: [hocMixin],
// ... other component options
};
</script>
在这个例子中,hocMixin 包含一个名为 logMessage 的方法。通过在 YourComponent.vue 组件中引入并混入 hocMixin,YourComponent 现在可以使用 logMessage 方法。
2、函数化组件(Functional Component)
函数化组件是无状态的,没有实例,只有 props 和 context 参数的组件。你可以使用函数化组件来创建一个接收组件作为参数并返回一个新组件的高阶组件。以下是一个使用函数化组件的简单例子:
// hocFunctional.js
export default function hocFunctional(WrappedComponent) {
return {
functional: true,
render(h, context) {
// 添加新的功能
console.log('HOC Functional Log: ', context.props.message);
// 渲染原始组件
return h(WrappedComponent, context.data, context.children);
},
};
}
// YourComponent.vue
<template>
<div>
<button @click="logMessage('Button Clicked')">Click me</button>
</div>
</template>
<script>
import hocFunctional from './hocFunctional';
export default hocFunctional({
props: {
message: String,
},
// ... other component options
});
</script>
在这个例子中,hocFunctional 是一个高阶组件函数,它接受一个被包装的组件 WrappedComponent 作为参数。它返回一个新的函数化组件,该组件在渲染时输出日志,并渲染原始组件。
这两种方法都允许你在 Vue 中实现高阶组件的模式,具体选择取决于你的需求和喜好。