HOC高阶组件初体验
什么是高阶组件:
简单的来说就是抽离具有相同逻辑或者相同展示的组件,用来提高组件复用率。
从本质上来讲高阶组件就是一个函数。这个函数接收了一个组件,并返回一个新的组件,返回的这个新组件可以对属性进行包装,也可以重写部分生命周期
简单案例
这是利用react脚手架创建的简单案例
入口文件index.js
import ReactDOM from 'react-dom'
import React from 'react'
import App from './App.jsx'
ReactDOM.render(<App/>,document.getElementById('root'))
APP组件App.jsx
import React, { Component } from 'react';
//第一步:创建一个高阶组件,传入一个组件,返回一个新的组件
const withHighOrder = (Component) => {
//将传入组件的原有的属性作为参数重新传入新的组建中去
const NewComponent = (props) => {
//利用ES6 ...属性扩散的新特性,将属性全部接受,并传入一个新的属性
return <Component {...props} name="重新包装给定的新属性"></Component>
}
return NewComponent
}
class App extends Component {
render() {
return (
<div>
<h1>react高阶组件学习</h1>
{/* 第三步:接收传递进来的属性,根据需要去使用 */}
{this.props.name}
</div>
);
}
}
//第二步,给创建的高阶组件传递需要重新包装的属性,这里是给App组件重新包装
export default withHighOrder( App ) ;
最终效果:
这里的话我大概总结一下简单高阶组件创建步骤:
- 定义一个高阶组件,给高阶组件传入需要重新包装的组件作为参数
- 在高阶组件内部创建一个新的组件,并将传入的组件的属性,传递参数,返回的新组建中重新包装需要给定的新的属性
- 高阶函数最后返回的是一个已经被包装过的新的组件
- 将我们需要包装的App组件作为参数,传递给高阶函数
withHighOrder(App)
- 最后在需要的位置去应用传递进来的新属性
注意点:
- 高阶组件命名一般以with开头
- 千万不能忘记利用
{...props}
进行属性传递,不然新的包装还没用上,旧的属性也没得用 - 一定要记得高阶函数最后的返回
return NewComponent
- 这里的话我没有去给App设立原有的属性,需要给App设立原有属性的话可以通过入口文件
index.js
中的<App/>
给他传递你想要的属性
重写生命周期函数
刚刚的话我们这个简单的案例只是将组件重新包装了一下,给他传递了新的属性,接下来的话就是利用高阶函数的特性,给这个组件重写生命周期,同是我们可以达到链式调用的目的
先单独把重写生命周期函数这一块的高阶组件代码列出来
const withLifeCycle = (Component) => {
//创建新的组件,重写生命周期并返回
class NewComponent extends React.Component{
//重写componentDidMount方法
componentDidMount(){
console.log('重写生命周期函数')
}
render(){
return <Component {...this.props}></Component>
}
}
return NewComponent
}
这里的话就是重写组件生命周期的高阶组建的代码内容,在最外层创建这个高阶函数,里面再创建一个新的class组件,在class组件中重写生命周期
最后通过刚才的方式我们再把新的组件暴露出去 withLifeCycle(App)
就可以重写App的生命周期函数了,当然,如果我们原来就有过componentDidMount
生命周期函数,也会先被执行
链式调用
使用情况如下:
- 编写一个高阶组件进行属性的添加
- 编写一个高阶组件编写生命周期
- 然后将以上两个高阶组件进行链式调用
现在的话我们就已经拥有了以上两点,属性和生命周期都可以进行更改,可以直接通过链式调用withLifeCycle( withHighOrder( App ))
因为withHighOrder( App )
返回的还是一个组件,那么withLifeCycle()
还是可以调用其返回的组件,这就实现了链式调用
完整App.jsx
代码如下:
import React, { Component } from 'react';
//第一步:创建一个高阶组件,传入一个组件,返回一个新的组件
const withHighOrder = (Component) => {
//将传入组件的原有的属性作为参数重新传入新的组建中去
const NewComponent = (props) => {
//利用ES6 ...属性扩散的新特性,将属性全部接受,并传入一个新的属性
return <Component {...props} name="重新包装给定的新属性"></Component>
}
return NewComponent
}
//创建新的高阶组件,重写生命周期
const withLifeCycle = (Component) => {
//创建新的组件,重写生命周期并返回
class NewComponent extends React.Component{
//重写componentDidMount方法
componentDidMount(){
console.log('重写生命周期函数')
}
render(){
return <Component {...this.props}></Component>
}
}
return NewComponent
}
class App extends Component {
render() {
return (
<div>
<h1>react高阶组件学习</h1>
{/* 第三步:接收传递进来的属性,根据需要去使用 */}
{this.props.name}
</div>
);
}
}
//第二步,给创建的高阶组件传递需要重新包装的属性,这里是给App组件重新包装
export default withLifeCycle( withHighOrder( App ));
效果图:
那么以上基本的高阶组件的使用就已经完成了。可以再对其进行扩展,之后的话我会专门再出一些经典的高阶组件使用的小案例,提供学习用。
装饰器的使用
其实我们会发现那么长一段的链式调用其实很复杂,也很绕,所以呢我们可以采用ES7提供的语法, 装饰器 ,专门来解决这种组件之间层层嵌套的问题,总结就是它是先走的,它放在谁的头上都是先执行装饰器函数然后再指定当前的函数,装个装饰器就可以对对象中的state,props进行修改,直接影响就是展示效果
create-react-app默认不支持装饰器的,需要做以下配置。
1.终端运行npm run eject
,暴露项目的配置项,如果失败的话,则运行
git add .
git commit -m “commit”
2.安装babel插件
npm install --save-dev @babel/plugin-proposal-decorators
3.修改package.json文件的babel配置项
"babel": {
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }]
],
"presets": [
"react-app"
]
}
至此,就可以在我们的项目中使用装饰器了
附上利用装饰器的App.jsx
简易版代码
import React, { Component } from 'react';
//第一步:创建一个高阶组件,传入一个组件,返回一个新的组件
const withHighOrder = (Component) => {
//将传入组件的原有的属性作为参数重新传入新的组建中去
const NewComponent = (props) => {
//利用ES6 ...属性扩散的新特性,将属性全部接受,并传入一个新的属性
return <Component {...props} name="重新包装给定的新属性"></Component>
}
return NewComponent
}
//创建新的高阶组件,重写生命周期
const withLifeCycle = (Component) => {
//创建新的组件,重写生命周期并返回
class NewComponent extends React.Component{
//重写componentDidMount方法
componentDidMount(){
console.log('重写生命周期函数')
}
render(){
return <Component {...this.props}></Component>
}
}
return NewComponent
}
@withHighOrder
@withLifeCycle
class App extends Component {
render() {
return (
<div>
<h1>react高阶组件学习</h1>
{/* 第三步:接收传递进来的属性,根据需要去使用 */}
{this.props.name}
</div>
);
}
}
//第二步,给创建的高阶组件传递需要重新包装的属性,这里是给App组件重新包装
export default App ;
利用了装饰器我们在最后就不需要再一长串的withLifeCycle( withHighOrder( App ))
去调用了,只需要在我们需要调用高阶函数的组件前去调用即可。这里要注意,一定要先声明高阶函数再去调用。不可以@高阶组件
都从上到下出来了,高阶组件的内容还在更下面。这样是访问不到高阶组件的。
那到这里的话高阶组件的基本几个知识点就已经讲完了,到后面有机会的话我再出几个高阶组件的案例,简单的实际去用上这个高阶组件。