HOF:Higher-Order Function, 高阶函数,以函数作为参数,并返回一个函数,例如(compose、bind)
HOC: Higher-Order Component, 高阶组件,以组件作为参数,并返回一个组件。
如下例代码B,返回一个新的组件,所以B就是一个高阶组件。
import React from 'react'
export default function withTest(comp) {
return class extends React.Component{
}
}
function A(){
return <h1>test</h1>
}
const B = withTest(A);
如果我们要设计一个日志记录组件,那么想想怎样能让这个日志记录组件复用性更高,后期更好维护呢?将整个日志记录组件封装成一个组件?
//withLog.js
import React from 'react'
export default function withLog(Comp) {
// 使用传入的记录器组件进行记录
return class LogWarpper extends React.Component {
// 取个名字方便后期调试
componentDidMount() {
console.log(`日志:组件${
Comp.name}被创建了!${
Date.now()}`);
}
componentWillUnmount() {
console.log(`日志:组件${
Comp.name}被销毁了!${
Date.now()}`);
}
render(){
return <Comp />
}
}
}
如下两个记录器A、B,如果想实现两个记录器,那么难以避免造成代码重复,索性交给另一个组件专门去实现如何进行记录,然后调用A,B即可。
//Comp.js
import React from 'react'
export class A extends React.Component{
// A记录器
render() {
return <h1>A</h1>
}
}
export class B extends React.Component{
// B记录器
render() {
return <h1>B</h1>
}
}
import React, {
Component } from 'react'
import {
A,B} from './components/Comps'
import withLog from './HOC/withLog'
const ALog = withLog(A);
const BLog = withLog(B);
export default class Input extends Component {
render() {
return (
<div>
<ALog />
<BLog />
</div>
)
}
}
这里就很明显了,A,B只会记录事件,如何记录是LogWarpper的事;两个组件分开也能实现一些功能,组合起来则能产生1+1>2的效果。
组件通过嵌套,那么属性当然也需要我们自己手动一层一层向下传递。
//withLog.js
import React from 'react'
export default function withLog(Comp) {
return class LogWarpper extends React.Component {
componentDidMount() {
console.log(`日志:组件${
Comp.name}被创建了!${
Date.now()}`);
}
componentWillUnmount() {
console.log(`日志:组件${
Comp.name}被销毁了!${
Date.now()}`);
}
render(){
return <Comp {
...this.props} />
}
}
}
//Comps.js
import React from 'react'
export class A extends React.Component{
render() {
return <h1>A:{
this.props.a}</h1>
}
}
export class B extends React.Component{
render() {
return <h1>B:{
this.props.b}</h1>
}
}
import React, {
Component } from 'react'
import {
A,B} from './components/Comps'
import withLog from './HOC/withLog'
const ALog = withLog(A);
const BLog = withLog(B);
export default class Input extends Component {
render() {
return (
<div>
<ALog a={
'a'} />
<BLog b={
'b'} />
</div>
)
}
}
模拟一个登录系统,只有当提取到登录信息isLogin后才能显示后续页面。
//withLogin
import React from 'react'
export default function withLogin(Comp) {
return function LoginWrapper(props) {
if(props.isLogin){
return <Comp {
...props} />
}
return null;
}
}
Comp并未有任何改变
//Comp.js
import React from 'react'
export class A extends React.Component{
render() {
return <h1>A:{
this.props.a}</h1>
}
}
export class B extends React.Component{
render() {
return <h1>B:{
this.props.b}</h1>
}
}
如果不传isLogin
import React, {
Component } from 'react'
import {
A,B} from './components/Comps'
import withLogin from './HOC/withLogin'
const ALog = withLogin(A);
const BLog = withLogin(B);
export default class Input extends Component {
render() {
return (
<div>
<ALog a={
'a'} />
<BLog b={
'b'} />
</div>
)
}
}
传入isLogin后
是不是发现高阶组件的用处大大的了?其用处当然不止如此,还可以配合我们实现各种复杂的逻辑。
如果我们render函数内去包装一个高阶组件呢?
import React, {
Component } from 'react'
import {
A,B} from './components/Comps'
import withLog from './HOC/withLog'
export default class Input extends Component {
render() {
const ALog = withLog(A);
const BLog = withLog(B);
return (
<div>
<ALog isLogin a={
'a'} />
<BLog isLogin b={
'b'} />
<button onClick={
()=>{
this.setState({
})
}}>点击</button>
</div>
)
}
}
一旦我们对状态进行操作时,你会发现,组件并没有进行重用单独刷新数据,而是整个组件都销毁冲建了。这会对性能造成影响。
此外不要在高阶组件内部更改传入的组件