摘要:创建一个普通函数因为的存在所以变成构造函数创建一个方法在方法中,创建一个中间实例对中间实例经过逻辑处理之后返回使用方法创建实例而恰好,高阶组件的创建逻辑与使用,与这里的方法完全一致。因为方法其实就是构造函数的高阶组件。
很多人写文章喜欢把问题复杂化,因此当我学习高阶组件的时候,查阅到的很多文章都给人一种高阶组件高深莫测的感觉。但是事实上却未必。
有一个词叫做“封装”。相信写代码这么久了,大家对这个词所表达的含义都不会陌生。我们通常会将功能相同或者相似的代码提取出来封装成为一个可共用的函数或者对象,这也是我们从初学者慢慢进阶的必经之路。而高阶组件就是一个封装行为。
但是高阶组件的封装与我们通常所使用的不太一样,如果完全一样也就不是那么难理解了。好在我们有一个常用的口头语“包一层“刚好可以用来简单解释高阶组件的不同。在普通组件外面包一层逻辑,就是高阶组件。
关于”包一层“,可以通过一个非常简单的例子来理解。
import React, { Component } from "react"; class Div extends Component { componentDidMount() { console.log("这是新增的能力"); } render () { return ({ this.props.children }) } } export default Div;
在上面的例子中,我们把html的DIV标签作为基础元件。对他新增了一个输出一条提示信息的能力。而新的Div组件,就可以理解为div标签的高阶组件。到这里希望大家已经理解了包一层的具体含义。
为了更加透彻的理解“包一层”的概念,我们需要来回顾一下new与构造函数之间的关系。在前面我有文章提到过为什么构造函数中this在运行时会指向new出来的实例,不知道还有没有人记得。我将那段代码复制过来。
// 先一本正经的创建一个构造函数,其实该函数与普通函数并无区别 var Person = function(name, age) { this.name = name; this.age = age; this.getName = function() { return this.name; } } // 将构造函数以参数形式传入 function New(func) { // 声明一个中间对象,该对象为最终返回的实例 var res = {}; if (func.prototype !== null) { // 将实例的原型指向构造函数的原型 res.__proto__ = func.prototype; } // ret为构造函数执行的结果,这里通过apply,将构造函数内部的this指向修改为指向res,即为实例对象 var ret = func.apply(res, Array.prototype.slice.call(arguments, 1)); // 当我们在构造函数中明确指定了返回对象时,那么new的执行结果就是该返回对象 if ((typeof ret === "object" || typeof ret === "function") && ret !== null) { return ret; } // 如果没有明确指定返回对象,则默认返回res,这个res就是实例对象 return res; } // 通过new声明创建实例,这里的p1,实际接收的正是new中返回的res var p1 = New(Person, "tom", 20); console.log(p1.getName()); // 当然,这里也可以判断出实例的类型了 console.log(p1 instanceof Person); // true
在上面的例子中,首先我们定义了一个本质上与普通函数没区别的构造函数,然后将该构造函数作为参数传入New函数中。我在New函数中进行了一些的逻辑处理,让New函数的返回值为一个实例,正因为New的内部逻辑,让构造函数中的this能够指向返回的实例。这个例子就是一个“包一层”的案例。如果因为基础不够扎实导致你对上面的例子确实理解不了,我们还可以简单粗暴的把上面的例子分成三个步骤来记忆。
创建一个普通函数(因为new的存在所以变成构造函数)
创建一个new方法
在new方法中,创建一个中间实例res
对中间实例res经过逻辑处理之后返回res
使用new方法创建实例
而恰好,高阶组件的创建逻辑与使用,与这里的new方法完全一致。因为new方法其实就是构造函数的”高阶组件“。按照这个步骤,我们来尝试一步一步创建一个高阶组件。
第一步,创建一个最简单的基础组件。
class Basic extends Component { render() { return ({ this.props.children }) } }
第二步,根据上栗new方法的步骤,来创建高阶组件。
// src/Addsss.jsx import React from "react"; // 基础组件作为高阶组件的参数传入 function Addsss(Container) { // 创建一个中间组件,该中间组件会在添加了逻辑之后返回 return class Asss extends React.Component { componentDidMount() {} render() { return ( // 高阶组件往基础组件中传入了一个name属性,这是高阶组件赋予基础组件的新能力,当然,根据实际需求还可以添加更为复杂的新能力{ this.props.children } ) } } } export default Addsss;
高阶组件在基础组件中调用,并将高阶组件的运行结果返回给模块外部。因此基础组件的代码调整如下:
// src/basic.jsx import React, { Component } from "react"; import Addsss from "./Addsss"; class Basic extends Component { componentDidMount() { // 在基础组件中试图访问高阶组件传入的新参数 console.log(this.props.name); } render() { return ({ this.props.children }) } } // 这里相当于执行了一次new操作,返回了一个实例,其实运行结果真是高阶组件中的中间组件 export default Addsss(Basic);
我们看到其实在基础组件中,对外抛出的接口是Addsss(Basic),这是高阶组件里定义的函数运行的结果。也就是说,其实基础组件中返回的是高阶组件中定义的Asss中间组件。这和new的思路几乎完全一致。
所以我们可以简单理解为:react组件的高阶组件,就是在基础react组件外面包一层,给该基础组件赋予新的能力。
当然,想要熟练使用高阶组件并不是一件容易的事情,我们还需要更多的思考他。在下面一篇文章中我将会以实际的案例来分析高阶组件的使用场景与他到底给我们带来了哪些便利。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/83689.html
摘要:前面有讲到过很多页面会在初始时验证登录状态与用户角色。这个时候就涉及到一个高阶组件的嵌套使用。而每一个高阶组件函数执行之后中所返回的组件,刚好可以作为下一个高阶组件的参数继续执行,而并不会影响基础组件中所获得的新能力。 前面有讲到过很多页面会在初始时验证登录状态与用户角色。我们可以使用高阶组件来封装这部分验证逻辑。封装好之后我们在使用的时候就可以如下: export default w...
摘要:在前端基础进阶八深入详解函数的柯里化一文中,我有分享柯里化相关的知识。虽然说高阶组件与柯里化都属于比较难以理解的知识点,但是他们组合在一起使用时并没有新增更多的难点。 可能看过我以前文章的同学应该会猜得到当我用New的方法来举例学习高阶组件时,接下来要分享的就是柯里化了。高阶组件与函数柯里化的运用是非常能够提高代码逼格的技巧,如果你有剩余的精力,完全可以花点时间学习一下。 在前端基础进...
摘要:高阶组件可以封装公共逻辑,给当前组件传递方法属性,添加生命周期钩子等。二是基础组件的静态方法也会因为高阶组件的包裹会丢失。如果在开发中确实遇到了必须使用它们,就一定要注意高阶组件的这个问题并认真解决。 高阶组件可以封装公共逻辑,给当前组件传递方法属性,添加生命周期钩子等。 案例: 一个项目中有的页面需要判断所处环境,如果在移动端则正常显示页面,并向用户提示当前页面所处的移动端环境,如果...
摘要:课程制作和案例制作都经过精心编排。对于开发者意义重大,希望对有需要的开发者有所帮助。是从提案转为正式加入的新特性。并不需要用继承,而是推荐用嵌套。大型项目中模块化与功能解耦困难。从而更加易于复用和独立测试。但使用会减少这种几率。 showImg(https://segmentfault.com/img/bVbpNRZ?w=1920&h=1080); 讲师简介 曾任职中软军队事业部,参与...
阅读 464·2021-10-09 09:57
阅读 468·2019-08-29 18:39
阅读 809·2019-08-29 12:27
阅读 3026·2019-08-26 11:38
阅读 2665·2019-08-26 11:37
阅读 1284·2019-08-26 10:59
阅读 1374·2019-08-26 10:58
阅读 988·2019-08-26 10:48