• 日常搜索
  • 百度一下
  • Google
  • 在线工具
  • 搜转载

React中高阶组件 (HOC) 介绍

高阶组件 (HOC) 是react中的一种有趣技术,用于重构具有几乎相同逻辑的相似组件。我知道这听起来很抽象和高级。但是,它是一种架构模式,并非特定于 React,因此您可以使用该方法来做很多事情。 

例如,您可以使用它向某个组件添加加载指示器,而无需调整原始组件,或者您可以隐藏组件的 props 以使其不那么冗长。应用程序很多,我已尝试在本教程中介绍其中的大部分。

还有其他几个教程可以教你关于 HOC 的知识,但其中大部分是为高级 React 开发人员准备的。当我开始学习 React 时,我很难理解高阶组件的概念以及如何将 HOC 合并到我的项目中以编写更好的代码。本文将从头到尾解释您需要了解的有关 HOC 的所有信息。 

概述

本教程分为三个部分。第一部分将作为对高阶组件概念的介绍。在这里,我们将讨论在查看高阶函数和 HOC 之前需要了解的语法。第二部分是本系列中最令人高兴的部分,您将看到 HOC 的实际示例。我们将使用 HOC 来创建表单、授权和许多其他事情。 

在本教程的第三部分,我们将更多地关注最佳实践和实现高阶组件时要考虑的事项。我们还将简要介绍 React 中代码共享的替代模式,例如 Render props。

在开始之前,最好先看看有状态与无状态组件的教程,以更好地了解 React 的组件架构。

ES6 语法备忘单

我们很快就会弄脏手。但在我们这样做之前,这里有一些我认为你应该知道的事情。我更喜欢尽可能使用 ES6 语法,它与 HOC 配合得很好。作为初学者,HOC 是有意义的,但一些 ES6 语法却没有。所以我建议你把这部分看一遍,你可以稍后再回来参考。 

箭头函数

箭头函数是正则函数表达式,但语法更短。它们最适合非方法函数,这是我们特别感兴趣的。这里有一些示例可以帮助您入门:

参数功能

/* Functions without parameters */
function () {
    return "This is a function expression";
}

// is equivalent to

() => {
 return "This is an arrow function expression"
}

// or 

() => "Arrow with a shorter syntax"

具有单个参数的函数

/* Function with a single parameter */

function (param) {
  return { title: "This function accepts a parameter and returns an object",
          params: param}
}

// is syntax-equivalent to 

param => {
    return { title: "This arrow function accepts a single parameter",
        params: param }
}

多参数函数

/* Function with multiple parameters */

function (param1, param2) {
  return { title: "This function accepts multiple parameters",
          params: [param1,param2]}
}

// is syntax-equivalent to 

(param1, param2) => {
    return {title: "Arrow function with multiple parameters",
    params: [param1, param2]
    }
}

// or

(param1, param2) => ({
      title: "Arrow function with multiple parameters",
    params: [param1, param2]
    })

函数式编程中的柯里化

虽然这个名字暗示它与流行的印度菜中的异国菜肴有关,但事实并非如此。柯里化可帮助您将一个接受多个参数的函数分解为一系列一次接受一个参数的函数。这是一个例子:

//Usual sum function
const sum = (a, b) => a + b

//Curried sum function 
const curriedSum = function (a) {
    return function (b) {
        return a+b
    }

//Curried sum function using arrow syntax
const curriedSum = a => b => a+b

curriedSum(5)(4)
//9

该函数只接受一个参数并返回一个接受另一个参数的函数,并继续进行,直到满足所有参数为止。 

curriedSum
// (a) => (b) => a+b

curriedSum(4)

// (b) => 4+b

curriedSum(4)(5)

//4+5

一个密切相关的术语称为部分应用。部分应用程序通过预先填充现有函数的一些参数来处理创建新函数。新创建的函数将具有比原始函数少的数量(转换为参数的数量)。

传播语法

扩展运算符扩展数组、字符串或对象表达式的内容。这是您可以使用扩展运算符执行的操作列表

函数调用中的扩展语法

/*Spread Syntax in Function Calls */
const add = (x,y,z) => x+y+z

const args = [1,2,3]

add(...args) 
// 6

数组文字中的扩展语法

/* Spread in Array Literals */

const twoAndThree = ['two', 'three']; 
const numbers = ['one', ...twoAndThree, 'four', 'five']; 
// ["one", "two", "three", "four", "five"]

对象文字中的传播语法

/* Spread in Object Literals */

const contactName = {
  name: {
    first: "Foo",
    middle: "Lux",
    last: "Bar"
  }
}
const contactdata = {
  email: "fooluxbar@example.com",
  phone: "1234567890"
}

const contact = {...contactName, ...contactData}
/* { 
    name: {
        first: "Foo",
        middle: "Lux",
        last: "Bar"
    }
    email: "fooluxbar@example.com"
    phone: "1234567890"
  }
  
*/

我个人喜欢三个点可以让您更轻松地将现有道具传递给子组件或创建新道具的方式。

React 中的扩展运算符

const ParentComponent = (props) => {
  const newProps = { foo: 'default' };
  
  return (
      <ChildComponent 
  		{...props} {...newProps} 
  	/>
  )
}

现在我们知道了构建 HOC 的基本 ES6 语法,让我们看看它们是什么。

高阶函数

什么是高阶函数?维基百科有一个简单的定义:

在数学和计算机科学中,高阶函数(也称为函数、函数形式或函子)是一种函数,它可以将一个或多个函数作为参数,或者将函数作为结果返回,或者两者兼而有之。

您之前可能以一种或另一种形式在javascript中使用过高阶函数,因为这就是 JavaScript 的工作方式。传递匿名函数回调作为参数或返回另一个函数的函数——所有这些都属于高阶函数。下面的代码创建了一个本质上更高阶的计算器函数。 

const calculator = (inputFunction) => 
    	(...args) => {
        
       const resultValue = inputFunction(...args);
       console.log(resultValue);
          
       return resultValue;
        }

const add = (...all) => {
	return all.reduce( (a,b) => a+b,0)	;
  
	}
  
 
const multiply = (...all) => {
  return all.reduce((a,b)=> a*b,1);
 
  }

让我们更深入地了解一下。calculator()接受一个函数作为输入并返回另一个函数——这完全符合我们对高阶函数的定义因为我们使用了其余参数语法,所以返回的函数将其所有参数收集在一个数组中。 

然后,使用传递的所有参数调用输入函数,并将输出记录到控制台所以计算器是一个柯里化的高阶函数,你可以像这样使用你的计算器:

calculator(multiply)(2,4);
// returns 8

calculator(add)(3,6,9,12,15,18); 
// returns 63

插入一个函数,例如add()ormultiply()和任意数量的参数,然后calculator()从那里获取它。所以计算器是一个容器,它扩展了add()和的功能multiply()它使我们能够在更高或更抽象的层次上处理问题。一目了然,这种方法的好处包括:

  1. 代码可以跨多个函数重用。

  2. 您可以在容器级别添加所有算术运算通用的额外功能。 

  3. 它更具可读性,并且更好地表达了程序员的意图。

现在我们对高阶函数有了一个很好的了解,让我们看看高阶组件有什么能力。

高阶组件

高阶组件是接受组件作为参数并返回该组件的扩展版本的函数。 

(InputComponent) => {
    return ExtendedComponent 
    }
    
// or alternatively

InputComponent => ExtendedComponent

ExtendedComponent 组成InputComponentExtendedComponent就像一个容器它渲染了InputComponent,但是因为我们要返回一个新组件,所以它增加了一个额外的抽象层。您可以使用该层来添加状态、行为甚至样式。如果你愿意,你甚至可以决定根本不渲染InputComponent——HOC 能够做到这一点,甚至更多。

如果有的话,下面的图片应该可以消除混乱。

React中高阶组件 (HOC) 介绍  第1张

理论说完了——让我们来看看代码。这是一个非常简单的 HOC 示例,它将输入组件包装在<div>标签周围。从这里开始,我将使用InputComponentasWrappedComponent 因为这是惯例。但是,您可以随意调用它。

/* The `with` prefix for the function name is a naming convention.
You can name your function anything you want as long as it's meaningful 
*/

const withGreyBg = WrappedComponent => class NewComponent extends Component {
  
  const bgStyle = {
  		backgroundColor: 'grey',
	};
    
  render() {
    return (
      <div className="wrapper" style={bgStyle}>

        <WrappedComponent {...this.props} />
      </div>
    );
  }
};

const SmallCardWithGreyBg = withGreyBg(SmallCard);
const BigCardWithGreyBg = withGreyBg(BigCard);
const HugeCardWithGreyBg = withGreyBg(HugeCard);

class CardsDemo extends Component {
    render() {
        <SmallCardWithGreyBg {...this.props} />
        <BigCardWithGreyBg {...this.props} />
        <HugeCardWithGreyBg {...this.props />
    }
}

withGreyBg函数将一个组件作为输入并返回一个新组件。我们不是直接组合 Card 组件并将样式标签附加到每个单独的组件,而是创建一个用于此目的的 HOC。高阶组件包裹原始组件并<div>在其周围添加标签。需要注意的是,这里的道具需要手动下两层。我们没有做任何花哨的事情,但这就是普通 HOC 的样子。下图更详细地演示了该withGreyBg()示例。

React中高阶组件 (HOC) 介绍  第2张

尽管现在这似乎不是特别有用,但好处并非微不足道。考虑这种情况。您正在使用 React 路由器,并且您需要保护一些路由 - 如果用户未经过身份验证,则对这些路由的所有请求都应重定向/login我们可以使用 HOC 来有效地管理受保护的路由,而不是复制身份验证代码。想知道怎么做?我们将在下一个教程中介绍这一点以及更多内容。

注意:ECMAScript 中提出了一个称为装饰器的功能,可以轻松使用 HOC。但是,它仍然是一个实验性功能,所以我决定在本教程中不使用它。如果您使用的是create-react-app,则需要先弹出才能使用装饰器。如果您正在运行最新版本的 Babel(Babel 7),您需要做的就是安装 babel-preset-stage-0,然后将其添加到您的webpack .config.dev.js中的插件列表中,如下所示。 

// Process JS with Babel.
        {
            test: /\.(js|jsx|mjs)$/,
            include: paths.appSrc,
            loader: require.resolve('babel-loader'),
            options: {
              
              // This is a feature of `babel-loader` for webpack (not Babel itself).
              // It enables caching results in ./node_modules/.cache/babel-loader/
              // directory for faster rebuilds.
              cacheDirectory: true,
              presets: ['stage-0']
        },

概括

在本教程中,我们学习了 HOC 的基本概念。HOC 是构建可重用组件的流行技术。我们首先讨论了基本的 ES6 语法,以便您更容易习惯箭头函数和编写现代 javaScript 代码。

文章目录
  • 概述
  • ES6 语法备忘单
    • 箭头函数
      • 无参数功能
      • 具有单个参数的函数
      • 多参数函数
    • 函数式编程中的柯里化
    • 传播语法
      • 函数调用中的扩展语法
      • 数组文字中的扩展语法
      • 对象文字中的传播语法
      • React 中的扩展运算符
  • 高阶函数
  • 高阶组件
  • 概括