添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
好帅的铅笔  ·  postgresql - PHP ...·  9 月前    · 
打酱油的小蝌蚪  ·  Fit Bat command in ...·  1 年前    · 
飘逸的花卷  ·  kernel/Makefile:971: ...·  1 年前    · 
React组件封装技巧(HOC、Render Props、Hook)

React组件封装技巧(HOC、Render Props、Hook)

引言:在React项目开发的过程中,怎么减少代码冗余,提供代码质量,加强代码的可维护性,都是我们经常要考虑的问题。接下来,我会用HOC、Render Props、Hook这三种方式,示范一些常用的组件封装的技巧

一、HOC(高阶组件)

高阶组件(HOC)是 React 中用于复用组件逻辑的一种高级技巧。HOC 自身不是 React API 的一部分,它是一种基于 React 的组合特性而形成的设计模式。

可能之前没有详细了解过HOC的朋友,看到这个名词会比较陌生,以为自己没用过,其实,HOC早已在你的项目中广泛被用到,只不过是你没有留心注意而已。大家肯定写过以下代码

import { connect } from 'react-redux'
const HocDemoComponent = connect(
  mapStateToProps,
  mapDispatchToProps
)(DemoComponent)
// react-redux connect函数就返回一个高阶组

从上面的代码可以看出,高阶组件其实就是参数为组件,返回值为新组件的函数。

举一个简单的例子,比如说,我们有很多组件都会用到鼠标当前的位置,常规操作是,我们在每一个组件中去注册获取鼠标位置的方法。这样的话,代码比较冗余,而且维护的时候也不方便。

我们用HOC的方式实现下。

MousePoint.js //一个简单的位置信息的展示

import React from 'react'
import mousePositionHoc from '../hoc/MousePosition'
class MousePoint extends React.Component{
  constructor(props){
    super(props)
  render(){
    return(
        <span>鼠标的横坐标{this.props.positionX}</span>
        <span>鼠标的纵坐标{this.props.positionY}</span>
export default mousePositionHoc(MousePoint)

这是一个简单的组件,展示鼠标的横纵坐标的信息,props参数就是从我们的HOC封装函数中来。

MousePosition.js // HOC封装函数

import React from 'react'
export default (Component) => {
 return class WrappedComponent extends React.Component {
    constructor(props){
      super(props)
      this.state = {
        positionX: 0,
        positionY: 0
    componentDidMount() {
      document.addEventListener('mousemove', (e) => {
        this.setState({
          positionX: e.clientX,
          positionY: e.clientY
      }) // 在这里我们更新鼠标的位置,并存储在state中去,然后通过props传递给被传入的组件
    render(){
      return(
        <Component {...this.props} {...this.state}/>
        //props:这里返回的是WrappedComponent这个组件,所以本应该传递给Component组件的props,我们应该通过WrappedComponent传递下去
        //state: WrappedComponent可以操作自己的状态,我们可以将这些状态通过props的方式传递给Component组件

如果我们其他组件也想用到鼠标坐标的值的话,就不需要在componentDidMount中多次写相关的事件绑定了。只需要mousePosition(Component)就好。

以上就是一个高阶组件的实现方式。紧紧抓住一个概念”高阶组件其实就是参数为组件,返回值为新组件的函数“。

高阶组件可以用到很多的场景中去,打印日志、提取公共函数、调用公共api、渲染公共UI等等。

二、Render Props

React官方给出的定义是:Render Props是指一种在 React 组件之间使用一个值为函数的 prop 共享代码的简单技术

React Router中就用到了Render Props

<Route path="/home" render={() => <div>Home</div>} />

同样是鼠标位置信息这段逻辑,我们用Render Props实现方式如下:

import React from 'react'
import MousePoint from './MousePoint'
export default class MouseTracker extends React.Component{
  constructor(props){
    super(props)
  render(){
    return(
        <MousePoint
          render={(state) => {
            return(
                <span>鼠标横坐标是{state.positionX}</span>
                <span>鼠标纵坐标是{state.positionY}</span>

我们这里渲染一个MousePoint组件,这个组件接受一个render props,这个props不是简单的属性或者对象,而是一个函数。

import React from 'react'
export default class MousePoint extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      positionX: 0,
      positionY: 0
  componentDidMount() {
    document.addEventListener('mousemove', (e) => {
      this.setState({
        positionX: e.clientX,
        positionY: e.clientY
  render() {
    return ( 
          this.props.render(this.state)
}

我们在MousePoint组件中去执行这个render props,this.state为参数,函数拿到这个值后,成功渲染出鼠标的位置信息。

在React中,props可以传递任何对象,包括组件以及函数。通过这种自由组合的方式,我们能够实现非常功能。

说到这里,我们不得不提到this.props.children

import React from 'react'
export default class ChildComponent extends React.Component{
  constructor(props){
    super(props)
  render(){
    return(
        {this.props.children}
        {this.props.render}
function App() {
  return (
    <div className="App">
        <ChildComponent render={<p>This is a message</p>}>
          <p>Hello World</p>
        </ChildComponent>
}

这也是一种能够让我们封装代码的方式之一,不过一般用在样式的封装上。

this.props.children 指的就是组件start tag 和 end tag中间包括的部分。我们也可以通过props的方式去传递组件,像上面代码中render这样的方式。这就比较类似Vue中slot。

三、Hook

最后我们使用Hook的方式再实现一次获取鼠标位置逻辑

官方定义: Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

我们知道以往的函数组件只能当做展示组件,因为不能够使用React的生命周期和state,所以只能接受props,来渲染页面,react 16.8中引入了Hook这个概念,使函数式组件也具备class组件同样的特性。

我们先来自定义一个Hook

import React, { useState, useEffect } from 'react'
export default () => {
  const [positionX, setPositionX] = useState(0)
  const [positionY, setPositionY] = useState(0)
  const getMousePosition = (e) => {
    setPositionX(e.clientX)
    setPositionY(e.clientY)
  useEffect(() => {
    document.addEventListener('mousemove', getMousePosition)
    return () => {
      document.removeEventListener('mousemove', getMousePosition)
  return {
    positionX: positionX,
    positionY: positionY
}
import React, {
  useState,
  useEffect
} from 'react'
import useMousePosition from '../hooks/useMouse'