React提高05 高阶组件

已同步到个人博客,欢迎访问

什么是高阶组件

高阶组件(简称HOC)的目的就是实现代码的复用,它不是React的API,而是根据React的特性形成的一种开发范式。它接受一个组件作为参数并返回一个新的组件

function HOCFactory(WrappedComponent, ...args) {
  return class HOC extends React.Component {
    render(){
      return <WrappedComponent {...this.props} />
    }
  }
}

HOC中并没有修改输入的组件,也没有通过继承来扩展组件,而是通过组合的方式来达到扩展的目的

即:传入HOCFactory中的WrappedComponent是一个有个性的组件,而HOC中返回的class是有公共特性的组件,通过传入args一些配置参数,返回的就是这个特性组件和公共组件的组合组件

HOC可以做什么

  • 代码复用,代码模块化
  • 增删改props
  • 渲染劫持

(1)代码复用,代码模块化

看这样的一个例子:

加载数据、刷新数据的行为很常见,现在把这种逻辑抽离到高阶组件当中去。完成高阶组件loadAndRefresh,它具有以下功能:

class Post extends Component {
  render () {
    return (
      <div>
        <p>{this.props.content}</p>
        <button onClick={() => this.props.refresh()}>刷新</button>
      </div>
    )
  }
}

Post = loadAndRefresh('/post')(Post)

高阶组件loadAndRefresh接受一个url作为参数,然后返回一个接受组件作为参数的函数,这个新函数返回一个新的组件。新的组件渲染的时候会给传入的组件设置contentrefresh作为props

getData(url)的返回Promise,它返回一个字符串的文本,你需要通过contentprops把它传给被包裹的组件。组件在第一次加载还有refresh的时候会去服务器取数据。

另外,组件在加载数据的时候,content显示数据加载中...。而且,所有传给loadAndRefresh返回的组件的props要原封不动传给被包裹的组件。

最后一句话,loadAndRefresh返回的组件就是返回的新组件Post,被包裹的就是传入的原来的Post,原封不动就是指需要将this.props完全传递,利用了对象解构的语法

const getData = url => new Promise((resolve) => {
  setTimeout(resolve, 2000, Date.now())
});

class Post extends Component {
  render () {
    return (
      <div>
        <p>{this.props.content}</p>
        <button onClick={() => this.props.refresh()}>刷新</button>
      </div>
    )
  }
}

const loadAndRefresh = url => (Wrapper) => {
  return class extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        content: ''
      }
    };
    componentDidMount () {
      this.refresh()
    };
    async refresh() {
      this.setState({
        content: '数据加载中...',
      });
      const content = await getData(url);
      this.setState({
        content,
      });
    };
    render () {
      return (
        <Wrapper content={this.state.content} refresh={this.refresh.bind(this)} {...this.props}/>
      )
    }
  }
};

Post = loadAndRefresh('/post')(Post);

export default class PCHeader extends Component {
  render () {
    return (
      <Post />
    )
  }
}

上面的高阶组件中,接受了Post作为个性组件,而HOC中的公共组件部分实现的就是抽离出来的获取、刷新数据的逻辑(它也是一个组件)。

props的传递是通过在组件上,利用对象的扩展,将所有prop传入

(2)增删改props

HOC组件可以对传入的props进行修改或者添加

HOC组件会在原始组件的基础上增加一些扩展功能使用的props,这些props不应该传入到原始组件,一般会这样处理:

function control(wrappedComponent) {
  return class Control extends React.Component {
    render(){
      let props = {
        ...this.props,
        message: "You are under control"
      };
      return <wrappedComponent {...props} />
    }
  }
}

(3)渲染劫持

可以在HOC中控制是否渲染(这里控制的组件整体是否被渲染,而非组建内部的细节),无法在HOC中控制渲染细节

比如,组件在data没有加载完的时候加载LOADING,可以在HOC中这样实现:

function loading(wrappedComponent) {
  return class Loading extends React.Component {
    render(){
      if(!this.props.data) {
        return <div>LOADING...</div>
      }
      return <wrappedComponent {...props} />
    }
  }
}

注意事项

不要在render方法里面调用HOC方法

render里面每次调用HOC都会返回一个新的class,重新渲染会让性能损耗加大。

拷贝静态方法

有的时候在组件的class包装的静态方法,通过HOC返回的包装后的组件就没有这些静态方法。

为了保持组件使用的一致性,一般会把这些静态方法拷贝到包装后的组件上

function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  // Must know exactly which method(s) to copy :(
  Enhance.staticMethod = WrappedComponent.staticMethod;
  return Enhance;
}

例子

logger和debugger

官网的例子,可以用来监控父级组件传入的props的改变:

function logProps(WrappedComponent) {
  return class extends React.Component {
    componentWillReceiveProps(nextProps) {
      console.log(`WrappedComponent: ${WrappedComponent.displayName}, Current props: `, this.props);
      console.log(`WrappedComponent: ${WrappedComponent.displayName}, Next props: `, nextProps);
    }
    render() {
      // Wraps the input component in a container, without mutating it. Good!
      return <WrappedComponent {...this.props} />;
    }
  }
}

页面权限管理

可以使用HOC对组件进行包裹,当组件加载的时候,首先检验用户是否有对应的权限,如果有的话就渲染页面,如果没有就跳走

参考

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值