高阶组件
高阶组件 (HOC) 是 React 中用于重用组件逻辑的高级技术。HOC 本身并不是 React API 的一部分。它们是从 React 的组合性质中出现的一种模式。
高阶组件定义
根据官网介绍
高阶组件是一个接受一个组件并返回一个新的函数
代码语言:javascript复制const myComponent = HOC(subComponent)
存在两个逻辑相似,页面功能相似的页面,可以使用高阶函数去减少相同相似的代码,共享方法,和生命周期钩子函数
用法与注意事项(官网):
1.高阶组件是参数为组件,返回值为新组件的函数。 2.HOC 不会修改传入的组件,也不会使用继承来复制其行为。相反,HOC 通过将组件包装在容器组件中来组成新组件,HOC 是纯函数,没有副作用。 3.不要试图在 HOC 中修改组件原型 4.HOC 通常可以接收多个参数 4.不要在 render 方法中使用 HOC 5.务必复制静态方法 6.Refs 不会被传递,可使用React.forwardRef 解决
使用格式:
一般文件和方法名都是with开头
包装组件
普通包装
export 暴露
代码语言:javascript复制import React, { Component } from 'react'
export default Class Wrap extends Component {
render() {
return (
<div>{ this.props.name }</div>
)
}
}
import 包装
代码语言:javascript复制 import Wrap from './Wrap';
import withContainer from './HOC/withContainer'
const userContainer = withContainer(Wrap);
const userPage = () => {
return (
<div>
<userContainer name={'BobMary'} />
</div>
)
}
装饰器包装(只存在类class用法中)
代码语言:javascript复制import React, { Component } from 'react'
import withContainer from './HOC/withContainer'
@withContainer
export default class Wrap extends Component {
render() {
return (
<div>{ this.props.name }</div>
)
}
}
项目举例
项目需求
某个公司需要搬迁,需要系统采集登记已经搬迁的信息,包括:人员,物品,车辆。从A地区 搬迁到B地区。
需求分析
需要多个文件,实现的方式方法类似,展示的内容稍微不同,如果单独写每个文件,冗余代码较多,维护不便。
如果编写如下的代码,实现单个模块的逻辑,如果存在更细致的统计,那将复制粘贴出大量的相识相同的代码。
在假如,在搬迁的时候要求增加是谁负责某个模块,需要签名并实现流程化,那么这么多的模块都单独在增加,维护量和阅读量都非常的大
拓展( 应用场景)
- 1 路由配置:对路由进行封装,针对复杂树形导航与头部导航交替路由;也用于未登录未授权的用户的拦截
- 2 数据监控:加入埋点,分析数据
- 3 数据校验:表单的统一校验
- 4 数据异常处理:对报错数据进行处理,可以使用弹框提示,也可以进入埋点
- 5 权限判断:类似路由,点击按钮时,对页面的权限进行验证,在返回对应的路由或者弹框
// bad
import React, { Component} from 'react'
class GetGoodList extends Component {
constructor() {
this.state = {
...
}
}
handleChangeCheck(e, index, id) {
...
}
handleMoveSome() {
...
}
render() {
const { xxx } = this.state
return (
...
<span>car</span>
)
}
}
export default GetGoodList
如果要从人员,物品,车辆,分成三个文件独立维护,需要写大量重复的代码,因从我们需要将大部分逻辑代码提出来
HOC写法例子如下:
效果图:
代码语言:javascript复制import React, { Component } from 'react'
import SuperList from '../components/list/SuperLIst'
function withMove (WrapComponent, preData) {
return class MoveSomeToPlace extends Component {
constructor(props) {
super(props)
this.needMoves = []
this.state = { ...preData, hasMoved: []}
}
handleChangeCheck() {
return (e, index, id) => {
const { checked } = e.target
const { userListShow } = this.state
const position = this.needMoves.findIndex(e => e.id == id)
const isExist = position === -1
if (checked && isExist) {
this.needMoves.push(userListShow[index])
} else if (!checked && !isExist) {
this.needMoves.splice(position, 1)
}
userListShow[index].hasChecked = checked ? 'checked' : ''
this.setState({
userListShow
})
}
}
handleMoveSome() {
const data = [ ...this.needMoves ]
this.setState({
hasMoved: data
})
}
render() {
const { moveType, userListShow, hasMoved } = this.state
return (
<div className="c-stop-area">
<div className="need-move--left">
<SuperList lists={userListShow} needCheckbox
handleChangeCheck={this.handleChangeCheck()} />
</div>
<div>
<button className="c-btn" onClick={() => this.handleMoveSome()}>{moveType}</button>
</div>
<div className="has-moved--right">
<SuperList lists={hasMoved}
handleChangeCheck={this.handleChangeCheck()} />
</div>
<WrapComponent {...this.props}/>
</div>
)
}
}
}
export default withMove
三个不同的文件 ,数据和组件与之不同,但是完成的事相同,都是将A(左侧区域)的物品或人员通过勾选,入栈,在点击中间按钮进行移动(拷贝操作)最后呈现到B(右侧区域)
代码语言:javascript复制// 物品 搬运,数据列表不同
import React, { Component} from 'react'
import goodList from '../../mock/good'
import withMove from '../../HOC/withMove'
const goodSource = {
moveType: '搬运',
userListShow: goodList
}
class GetGoodList extends Component {
render() {
return (<span>good</span>)
}
}
export default withMove(GetGoodList, goodSource)
//=================================
// 人员 移动,数据列表不同
import React, { Component} from 'react'
import userList from '../../mock/user'
import withMove from '../../HOC/withMove'
const userSource = {
moveType: '移动',
userListShow: userList
}
class GetUserList extends Component {
render() {
return (<span>user</span>)
}
}
export default withMove(GetUserList, userSource)
//=================================
// 汽车 启动,数据列表不同
import React, { Component } from 'react'
import carList from '../../mock/car'
import withMove from '../../HOC/withMove'
const carSource = {
moveType: '启动',
userListShow: carList
}
class GetCarList extends Component {
render() {
return (<span>car</span>)
}
}
export default withMove(GetCarList, carSource)
持续更新,反向继承例子 与 ref使用