概念:HOC参数为组件,返回值为新组件的函数,通过组件嵌套给子组件添加了更多功能
作用:1. 代码提取,组件复用。2.劫持被处理组件的生命周期
第一项:原逻辑
import React, {useContext} from "react";
import { appSetStateContext} from '../AppState'
export interface RobotProps {
id: number;
name: string;
email: string;
}
// 组件传递数据使用的是props,接口定义传入的参数类型
const Robot: React.FC<RobotProps> = ({ id, name, email }) => {
const setState = useContext(appSetStateContext)
const addToCart = () => {
if (setState) {
setState(state => {
return {
...state,
shoppingCart: {
items: [
...state.shoppingCart.items,
{id, name}
]
}
}
})
}
}
return (
<li>
<button onClick={addToCart}>加入购物车</button>
</li>
);
};
export default Robot;
// FC functional component 函数式组件。FC默认有p = {}参数也就是props
第二项: 抽离业务代码之后
import React from "react";
1. 引入HOC
import {widthAddToCart} from './AddToCart'
2. 导出props的接口类型,HOC要用
export interface RobotProps {
id: number;
name: string;
email: string;
//addToCart 是在HOC中新增的prop,这里要使用可选链标识不是必传的
addToCart?: (id: number, name: string) => void
}
const Robot: React.FC<RobotProps> = ({ id, name, email, addToCart }) => {
return (
<li>
3. 通过props传过来的执行函数,执行并传入参数id,name
//由于props里面对addToCart使用了可选链,这里会提示addToCart可能是undefined,所以判断一下子
<button onClick={() => addToCart && addToCart(id, name)}>加入购物车</button>
</li>
);
};
4. 使用HOC包裹组件
export default widthAddToCart(Robot);
新建AddToCart文件
// AddToCart.tsx
import React, {useContext} from 'react'
import {appSetStateContext} from '../AppState'
1. 引入组件的props的类型定义
import {RobotProps} from './Robot'
规范:一般使用width开头
2. 类型RobotProps给到ChildComponent
export const widthAddToCart = (ChildComponent: React.ComponentType<RobotProps>) => {
// 返回类组件 return class extends React.Component {}
// 或者返回函数式组件
return (props:RobotProps) => {
const setState = useContext(appSetStateContext)
const addToCart = (id:number, name:string) => {
if (setState) {
setState(state => {
return {
...state,
shoppingCart: {
items: [
...state.shoppingCart.items,
{id, name}
]
}
}
})
}
}
3. 将逻辑执行函数addToCart,通过导出组件的props传递出去
return <ChildComponent {...props} addToCart={addToCart}/>
}
}
自定义hook
- hook是函数
- 命名以use 开头
- 内部可以调用其他hook函数
- 并非React的特性
使用自定义hook实现代码的提取,实现复用
相对于使用HOC提取共用代码,自定义hook的优势:代码清晰简洁,hook是纯函数,代码更易维护
// AddToCart.tsx
将widthAddCart 改成 useAddToCart
hook不需要引入React
import {useContext} from 'react'
import {appSetStateContext} from '../AppState'
export const useAddToCart = () => {
const setState = useContext(appSetStateContext)
const addToCart = (id:number, name:string) => {
if (setState) {
setState(state => {
return {
...state,
shoppingCart: {
items: [
...state.shoppingCart.items,
{id, name}
]
}
}
})
}
}
return addToCart
}
在组件中使用useAddToCart ,就比HOC更加简单
import {useAddToCart} from './AddToCart'
const Robot: React.FC<RobotProps> = ({ id, name, email }) => {
const addToCart = useAddToCart()
return (
<li>
<button onClick={() => addToCart(id, name)}>加入购物车</button>
</li>
);
};