高阶组件(HOC)是 React 中一项有趣的技术,用于重构共享几乎相同逻辑的类似组件。我知道这听起来很抽象而且很高级。然而,它是一种并非特定于 React 的架构模式,因此您可以使用该方法来做很多事情。
例如,您可以使用它向某个组件添加加载指示器,而无需调整原始组件,或者您可以隐藏组件的属性以使其不那么冗长。应用程序有很多,我试图在本教程中介绍其中的大部分。
还有其他几个教程可以教您有关 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()
或 multiply()
和任意数量的参数,以及 calculator()
将从那里拿走它。所以计算器是一个扩展了 add()
和 multiply()
功能的容器。它使我们能够在更高或更抽象的层面上处理问题。乍一看,这种方法的好处包括:
- 代码可以在多个函数中重复使用。
- 您可以在容器级别添加所有算术运算通用的额外功能。
- 更具可读性,并且能更好地表达程序员的意图。
现在我们对高阶函数有了一个很好的了解,让我们看看高阶组件的能力。
高阶组件
高阶组件是一个接受组件作为参数并返回该组件的扩展版本的函数。
(InputComponent) => { return ExtendedComponent } // or alternatively InputComponent => ExtendedComponent
扩展组件
组成 InputComponent
。 ExtendedComponent
就像一个容器。它呈现 InputComponent
,但因为我们返回一个新组件,所以它添加了一个额外的抽象层。您可以使用此层添加状态、行为甚至样式。如果您愿意,您甚至可以决定根本不渲染 InputComponent
— HOC 能够做到这一点以及更多。
下面的图片应该可以消除混乱(如果有的话)。
理论已经讲完了,让我们开始看代码。下面是一个非常简单的 HOC 示例,它将输入组件包装在
标记周围。从这里开始,我将把
InputComponent
称为
WrappedComponent
,因为这是惯例。不过,您可以随意命名它。
/* 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 来实现此目的。高阶组件包装原始组件并在其周围添加
标签。需要注意的是,这里你必须手动将 props 分两层传递下去。我们没有做任何花哨的事情,但这就是正常的 HOC 的样子。下图更详细地演示了
withGreyBg()
示例。
虽然这目前看起来不是特别有用,但好处并不小。考虑这种情况。您正在使用 React 路由器,并且需要保护某些路由 - 如果用户未经过身份验证,则对这些路由的所有请求都应重定向到 /login
。我们可以使用 HOC 来有效管理受保护的路由,而不是重复身份验证代码。好奇想知道怎么做吗?我们将在下一个教程中介绍这一点以及更多内容。
注意:ECMAScript 中提出了一个称为装饰器的功能,可以轻松使用 HOC。但是,它仍然是一个实验性功能,因此我决定不在本教程中使用它。如果您使用的是 create-react-app,则需要先弹出才能使用装饰器。如果您运行的是最新版本的 Babel (Babel 7),您所需要做的就是安装 <em>babel-preset-stage-0</em>
然后将其添加到 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 代码。
然后我们了解了高阶函数及其工作原理。最后,我们接触了高阶组件并从头开始创建了 HOC。
接下来,我们将通过实际示例介绍不同的 HOC 技术。在那之前请继续关注。在评论部分分享你的想法。
智能AI问答 智能助手能迅速回答你的编程问题,提供实时的代码和解决方案,帮助你解决各种难题。不仅如此,它还能提供编程资源和学习指导,帮助你快速提升编程技能。无论你是初学者还是专业人士,AI智能助手都能成为你的可靠助手,助力你在编程领域取得更大的成就。 我要提问 来源: 收藏 点赞 上一篇:Angular 服务:初学者综合指南 下一篇:获取数据的WP REST API 本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn 作者最新文章
- 春节前10个省份预计将遭遇持续时间最长的暴雪或大暴雪天气 2024-01-28 21:12:07
- 如何在酷狗直播房间点歌 2024-01-28 21:09:12
- 电视机主板维修需要付出多少费用? 2024-01-28 21:03:25
- 选择适合主板的固态硬盘的方法是什么? 2024-01-28 16:33:21
- 如何完成波斯王子遗失的王冠难度较高的支线任务 2024-01-28 15:33:11
- 设置华硕主板启动顺序的方法是什么? 2024-01-28 13:39:30
- 华硕主板超频指南 2024-01-28 13:36:30
- 如何正确进行主板放电,以及其作用是什么? 2024-01-28 13:33:22
- 官方升级拦截非法软件:第三方抢票软件不再具备速度优势 2024-01-28 13:03:29
- 谨防过年期间个人信息泄露!HarmonyOS 保障用户隐私安全不懈努力 2024-01-28 13:03:06
最新问题 李老师,第八节的JSON 原始数据 头这个是怎么弄出来的 李老师,第八节的JSON 原始数据 头这个是怎么弄出来的 茶壶来自于2024-01-23 22:03:34 0 0 275 Symfony 6 / Doctrine - 驱动程序发生异常:找不到驱动程序 我尝试设置我的symfony项目,一切都很好,因为我尝试创建学说数据库。我在.env文件中写入了DATABASE_URL,这是正确的,我想是这样,但是无论是我的本地xampp服务器... P粉729518806来自于2024-01-21 16:23:09 0 1 439 发现 XLSX 软件包漏洞,但没有更新的软件包 我在js代码中使用xls x。从去年开始就运转良好。今天我开始遇到问题并且构建失败。由于:$yarnaudit:yarnaudit v1.22.19┌───────────────... P粉221046425来自于2024-01-21 16:14:05 0 1 379 Vue 3中的组件导入 嗨,我正在尝试在Vue3中导入一个组件。这是我的组件结构:+src+App.vue+components+Navbar.vue在我的App.vue中我尝试过:<scripts... P粉564192131来自于2024-01-21 16:26:14 0 2 358 如何在Vue3中访问js文件中的Vue实例? 在Vue2中,我能够访问我的Vue实例以使用在Vue中注册的组件。测试.jsimportVuefrom'vue'exportfunctionrenderLogin(){Vue.to... P粉609866533来自于2024-01-21 16:04:50 0 2 510 Cookie权限导致iframe错误 我目前在我的网页中使用一个简单的iframe,使用bootstrap来适应小屏幕(=yout ubeShort)和大屏幕(=普通横向视频):<divclass="c... P粉447002127来自于2024-01-21 16:00:06 0 1 384 向 Vite 库构建添加类型:分步指南 我按照vite文档使用库模式,并且能够生成一个工作组件库。我使用vue-ts预设创建了项目,并在我的组件中定义了道具及其类型,并使用了一些接口。但是当我构建库时,没有包含任何类型。... P粉426780515来自于2024-01-21 15:57:45 0 2 390 为什么这段代码不能简单地打印出字母A到Z? <?phpfor($i='a';$i<='z';$i++)echo"$i\n";此代码段提供以下输出(换行符被空格替换):abcdefghijklm... P粉239089443来自于2024-01-21 15:39:33 0 2 310 Node.js 连接到 MySQL Docker 容器 ECONNREFUSED 在将此问题标记为重复之前,请注意我确实阅读了其他答案,但它并没有解决我的问题。我有一个包含两个服务的Dockercompose文件:version:"3"ser... P粉296080076来自于2024-01-21 15:41:18 0 1 357 将 CSV 文件导入 Firebase:分步指南 我发现我们可以将json文件导入到firebase中。我想知道是否有办法导入CSV文件(我的文件可能包含大约50K甚至更多记录,大约10列)。在firebase中拥有这样的文件是否... P粉891237912来自于2024-01-21 15:21:20 0 1 407 相关专题 更多>
- dandelion是什么
- 数据库三范式
- 搭建互联网服务器
- case when用法sql
- 安卓手机数据迁移到苹果手机
- attributeusage
- teambition
- 正则表达式不包含
2、本站所有文章、图片、资源等如果未标明原创,均为收集自互联网公开资源;分享的图片、资源、视频等,出镜模特均为成年女性正常写真内容,版权归原作者所有,仅作为个人学习、研究以及欣赏!如有涉及下载请24小时内删除;
3、如果您发现本站上有侵犯您的权益的作品,请与我们取得联系,我们会及时修改、删除并致以最深的歉意。邮箱: i-hu#(#换@)foxmail.com