当前位置: 首页 > news >正文

面试官:你是怎样进行react组件代码复用的

mixin

Mixin 设计模式

Mixin(混入)是一种通过扩展收集功能的方式,它本质上是将一个对象的属性拷贝到另一个对象上面去,可以拷贝多个属性到一个对象上,为了解决代码复用问题。

常用的方法:JQuery 的 extend 方法。

var LogMixin = {log: function() {console.log('log');},componentDidMount: function() {console.log('in');},componentWillUnmount: function() {console.log('out');}
};var User = React.createClass({mixins: [LogMixin],render: function() {return (<div>...</div>)}
});var Goods = React.createClass({mixins: [LogMixin],render: function() {return (<div>...</div>)}
});

缺点

  1. Mixin 可能会相互依赖,相互耦合,不利于代码维护
  2. 不同的 Mixin 中的方法可能会相互冲突
  3. 现在大量使用 ES6 语法后,React.createClass 已经取消,这种方式也不再推荐

高阶组件(HOC)

高阶组件的定义:

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

具体的意思就是:
高阶组件可以看作 React 对装饰模式的一种实现,高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。他会返回一个增强的 React 组件。高阶组件可以让我们的代码更具有复用性,逻辑性与抽象性,可以对 render 方法进行劫持,也可以控制 props 与 state。

const EnhancedComponent = higherOrderComponent(WrappedComponent);

实现高阶组件的两种方式:

  1. 属性代理: 高阶组件通过被包裹的 React 组件来操作 props
  2. 反向继承:高阶组件继承于被包裹的 React 组件。

属性代理

import React,{Component} from 'react';const HOC = (WrappedComponent) =>class WrapperComponent extends Component {state = { number: 0 };btnClick = () => {this.setState({number: this.state.number++})}render() {const newProps = {btnClick: this.btnClick,number: this.state.number}return (<div>rere HOC<WrappedComponent {...this.props} {...this.newProps} /></div>)}
}export default HOC;class MyComponent extends Component{//...
}export default HOC(MyComponent)

这里最重要的部分是render 方法中返回的 WrappedComponent 的 React 组件,这样就可以通过高阶组件来传递 props,这就是属性代理。

这样组件就可以一层层地作为参数被调用,原始组件就具备了高阶组件对它的修饰,也保持了单个组件的封装性,与易用性。参考 前端进阶面试题详细解答

特点

  1. 控制 props
    我们可以在 HOC 里面对 props 进行增删查改等操作

    const MouseHoc = (MouseComponent, props) => {props.text = props.text + "---I can operate props";return class extends React.Component {render() {return (<div style={{ height: "100%" }} onMouseMove={this.handleMouseMove}><MouseComponent {...props} mouse={this.state} /></div>);}};
    };
    MouseHoc(Mouse, {text: "some thing..."
    });
    
  2. 通过 refs 使用引用

    function refHOC(WrappedComponent) {return class extends Component {componentDidMount() {this.wapperRef.log();}render() {return (<WrappedComponent{...this.props}ref={ref => {this.wapperRef = ref;}}/>);}};
    }
    
  3. 抽象 state

  4. 渲染劫持
    高阶组件可以在 render 函数中做非常多的操作,从而控制原组件的渲染输出。只要改变了原组件的渲染,我们都将它称之为一种渲染劫持。

    function visibleHOC(WrappedComponent) {return class extends Component {render() {if (this.props.visible === false) return null;return <WrappedComponent {...props} />;}};
    }
    
  5. 使用其他元素包裹 WrappedCompoennt
    修改 props

反向继承

const MyContainer = (WrappedComponent) =>class extends WrappedComponent{render(){return super.render();}}

这里返回的组件继承了 WrappedComponent,因为被动地继承了 WrappedComponent,所有的调用都会反向。

注意事项

  1. 当我们应用 HOC 去增强另一个组件时,我们实际使用的组件已经不是原组件了,所以我们拿不到原组件的任何静态属性,我们可以在 HOC 的结尾手动拷贝他们

    function proxyHOC(WrappedComponent) {class HOCComponent extends Component {render() {return <WrappedComponent {...this.props} />;}}HOCComponent.staticMethod = WrappedComponent.staticMethod;// ...return HOCComponent;
    }
    
2. 不要在 render 方法内创建高阶组件3. 不要改变原始组件(高阶组件就是一个没有副作用的纯函数。)4. 透传不相关的 props### 解决的问题1. 高阶组件就是一个没有副作用的纯函数,各个高阶组件不会互相依赖耦合
2. 高阶组件也有可能造成冲突,但我们可以在遵守约定的情况下避免这些行为
3. 高阶组件并不关心数据使用的方式和原因,而被包裹的组件也不关心数据来自何处。高阶组件的增加不会为原组件增加负担### 存在的问题1. HOC 需要在原组件上进行包裹或者嵌套,如果大量使用 HOC,将会产生非常多的嵌套,这让调试变得非常困难
2. HOC 可以劫持 props,存在相同名称的 props,则存在覆盖问题在不遵守约定的情况下也可能造成冲突,而且 react 并不会报错。
3. 当存在多个 HOC 时,你不知道 Props 是从哪里来的。
4. HOC 属于静态构建,静态构建即是重新生成一个组件,即返回的新组件,不会马上渲染,即新组件中定义的生命周期函数只有新组件被渲染时才会执行。**在这个范式下,代码通过一个类似于 装饰器(decorator) 的技术进行共享。首先,你的一个组件定义了大量需要被渲染的标记,之后用若干具有你想用共享的行为的组件包裹它。因此,你现在是在 装饰 你的组件,而不是混入你需要的行为!## Render props> Render Props 从名知义,也是一种剥离重复使用的逻辑代码,提升组件复用性的解决方案。在被复用的组件中,**通过一个名为“render”(属性名也可以不是 render,只要值是一个函数即可)的属性,该属性是一个函数,这个函数接受一个对象并返回一个子组件,会将这个函数参数中的对象作为 props 传入给新生成的组件**。### 它的特点1. 传入函数的属性,就是  想要共享的 state,这个相同的 state 是组件的状态,或者行为
2. 术语 “render prop” 是指一种技术,用于使用一个值为函数的 prop 在 React 组件之间的代码共享。
3. render prop 仅仅就是一个函数。
4. `render prop`是一种模式,重点是 prop,而不是 render,任何被用于告知组件需要渲染什么内容的函数 prop 在技术上都可以被称为 “render prop”.
5. 这里的组合模型是 动态的!每次组合都发生在 render 内部,因此,我们就能利用到 React 生命周期以及自然流动的 props 和 state 带来的优势。
6. 具有 render prop 的组件接受一个函数,该函数返回一个 React 元素并调用它,而不是实现自己的渲染逻辑### 小栗子```xml
<DataProvider render={data => (<h1>Hello {data.target}</h1>
)}/>

优势

  1. 不用担心 Props 是从哪里来的, 它只能从父组件传递过来。
  2. 不用担心 props 的命名问题。
  3. render props 是动态构建的。

可以用 render props来代替 HOC

const withMouse = (Component) => {return class extends React.Component {render() {return <Mouse render={mouse => (<Component {...this.props} mouse={mouse}/>)}/>}}
}

Hook

在 Hooks 出现以前,我们总是纠结的问题:

  1. 无状态组件 VS Class 组件

  2. 生命周期
    componentDidMount 和 componentDidUpdate 需要做相同的事情

  3. this 指向
    为了保证 this 的指向正确,我们经常这么写

    this.handleClick = this.handleClick.bind(this)
    <button onClick={() => this.handleClick(e)}>
    
  4. HOC 和 render props 增加我们代码的层级关系

动机

Hook 的作用

  1. 我们的函数变成了一个有状态的函数
  2. Hooks 本质上就是一类特殊的函数,它们可以为你的函数型组件(function component)注入一些特殊的功能(生命周期钩子的功能:useEffect;上下文(context):useContext)
  3. 解决 this 指向问题

State Hooks

Effect Hooks

我们写的有状态组件,通常会产生很多的副作用(side effect)。之前都把这些副作用的函数写在生命周期函数钩子里,比如 componentDidMount,componentDidUpdate 和 componentWillUnmount。而现在的 useEffect 就相当与这些声明周期函数钩子的集合体。它以一抵三。

用 Effect Hooks 来解决这个这些副作用。

注意点

  1. react 首次渲染和之后的每次渲染都会调用一遍传给 useEffect 的函数。而之前我们要用两个声明周期函数来分别表示首次渲染(componentDidMount),和之后的更新导致的重新渲染(componentDidUpdate)。
  2. 函数是异步执行的,而之前的 componentDidMount 或 componentDidUpdate 中的代码则是同步执行的
  3. 怎么解绑副作用
  4. 跳过一些不必要的副作用函数

使用范围

只能在 React 函数式组件或自定义 Hook 中使用 Hook。

Hook 的提出主要就是为了解决 class 组件的一系列问题,所以我们不能在 class 组件中使用它。

相比函数,编写一个 class 可能需要掌握更多的知识,需要注意的点也越多,比如 this 指向、绑定事件等等。另外,计算机理解一个函数比理解一个 class 更快。Hooks 让你可以在 classes 之外使用更多 React 的新特性。

相关文章:

面试官:你是怎样进行react组件代码复用的

mixin Mixin 设计模式 Mixin&#xff08;混入&#xff09;是一种通过扩展收集功能的方式&#xff0c;它本质上是将一个对象的属性拷贝到另一个对象上面去&#xff0c;可以拷贝多个属性到一个对象上&#xff0c;为了解决代码复用问题。 常用的方法&#xff1a;JQuery 的 exte…...

arxiv2017 | 用于分子神经网络建模的数据增强 SMILES Enumeration

论文标题&#xff1a;SMILES Enumeration as Data Augmentation for Neural Network Modeling of Molecules论文地址&#xff1a;https://arxiv.org/abs/1703.07076代码地址&#xff1a;https://github.com/Ebjerrum/SMILES-enumeration一、摘要摘要中明显提出&#xff1a;先指…...

倒计时2天!TO B人的传统节日,2023年22客户节(22DAY)

去年&#xff0c;2022.02.22&#xff0c;正月二十二星期二&#xff0c;在这个最多2的一天&#xff0c;成功举办了“首届22客户节&#xff08;22DAY&#xff09;”&#xff0c;一群To B互联网人相约杭州见证&#xff1b; 癸卯兔年&#xff0c;2023.02.22&#xff0c;让我们再度…...

java版工程管理系统Spring Cloud+Spring Boot+Mybatis实现工程管理系统源码

java版工程管理系统Spring CloudSpring BootMybatis实现工程管理系统 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#xff1a;实现对数据字典标签的增删改查操作 2、编码管理&#xff1a;实现对系统编码的增删改查操作 3、用户管理&#xff1a;管理和…...

数据结构刷题(六):142环形链表II、242有效的字母异位词、383赎金信、349两个数组的交集

1.环形链表II题目链接思路&#xff1a;设置快慢双指针注意&#xff1a;&#xff08;1&#xff09;是否有环&#xff08;快慢双指针是否能碰面也就是相等&#xff09;&#xff08;2&#xff09;环形入口的判断。从头结点出发一个指针&#xff0c;从相遇节点 也出发一个指针&…...

OpenGL学习日记之光照计算

引言 现实生活中的光照极其复杂&#xff0c;而且会收到很多因素的影响&#xff0c;是我们当前计算机的算力无法模拟的。因此我们会根据一些简化的模型来模拟现实光照&#xff0c;这样在可以模拟出近似的光照感受&#xff0c;但是又没有那么复杂的计算。 常用的光照模型有&…...

七大排序经典排序算法

吾日三省吾身&#xff1a;高否&#xff1f;富否&#xff1f;帅否&#xff1f;答曰&#xff1a;否。滚去学习!!!(看完这篇文章先)目前只有C和C的功底&#xff0c;暂时还未开启新语言的学习&#xff0c;但是大同小异&#xff0c;语法都差不多。目录&#xff1a;一.排序定义二.排序…...

设计模式—“对象性能”

面向对象很好地解决了“抽象”的问题,但是必不可免地要付出一定的代价。对于通常情况来讲,面向对象的成本大都可以忽略不计。但是某些情况,面向对象所带来的成本必须谨慎处理。 典型模式有:Singleton、Flyweight 一、Flyweight 运用共享技术将大量细粒度的对象进项复用,…...

基于Spring Boot的零食商店

文章目录项目介绍主要功能截图&#xff1a;登录后台首页个人信息管理用户管理前台首页购物车部分代码展示设计总结项目获取方式&#x1f345; 作者主页&#xff1a;Java韩立 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关…...

Python语言的优缺点

为初学者而著&#xff01;适合准备入行开发的零基础员学习python。python也是爬虫、大数据、人工智能等知识的基础。感兴趣的小伙伴可以评论区留言&#xff0c;领取视频教程资料和小编一起学习&#xff0c;共同进步&#xff01;https://www.bilibili.com/video/BV13D4y1G7pt/?…...

3款强大到离谱的电脑软件,个个提效神器,从此远离加班

推荐3款让你偷懒&#xff0c;让你上头的提效电脑软件&#xff0c;个个功能强大&#xff0c;让你远离加班&#xff01; 很多几个小时才能做好的事情&#xff0c;用上它们&#xff0c;只需要5分钟就行&#xff01;&#xff01; 1、JNPF —— 个人最喜欢的低代码软件 它为开发者…...

vue3 使用typescript小结

最近学习vue3 typescript&#xff0c;网上看了很多文章&#xff0c;汇总一下&#xff0c;分享给大家&#xff0c;希望会对大家有帮助。 一. 为props标注类型 defineProps()宏函数支持从它的参数中推导类型&#xff1a; <script setup langts>import { defineProps } fro…...

PYTHON爬虫基础

一、安装package 在使用爬虫前&#xff0c;需要先安装三个包&#xff0c;requests、BeautifulSoup、selenium。 输入如下代码&#xff0c;若无报错&#xff0c;则说明安装成功。 import requests from bs4 import BeautifulSoup import selenium二、Requests应用 了解了原理…...

JavaScript刷LeetCode模板技巧篇(一)

虽然很多人都觉得前端算法弱&#xff0c;但其实 JavaScript 也可以刷题啊&#xff01;最近两个月断断续续刷完了 leetcode 前 200 的 middle hard &#xff0c;总结了一些刷题常用的模板代码。 常用函数 包括打印函数和一些数学函数。 const _max Math.max.bind(Math); co…...

ros-sensor_msgs/PointCloud2消息内容解释

1.字段解释 header-----头文件&#xff0c;包含消息的序列号&#xff0c;时间戳(系统时间)和坐标系id&#xff0c;其中secs为秒&#xff0c;nsecs为去除秒数后剩余的纳秒数 height-----点云的高度&#xff0c;如果是无序点云&#xff0c;则为1&#xff0c;例子中的点云为有序点…...

LeetCode 每日一题2347. 最好的扑克手牌

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法......感兴趣就关注我吧&#xff01;你定不会失望。 &#x1f308;个人主页&#xff1a;主页链接 &#x1f308;算法专栏&#xff1a;专栏链接 我会一直往里填充内容哒&#xff01; &…...

MMPBSA计算--基于李继存老师gmx_mmpbsa脚本

MMPBSA计算–基于李继存老师gmx_mmpbsa脚本 前期准备 软件安装 安装gromacs, 可以查阅 我的blogGromacs-2022 GPU-CUDA加速版 unbantu 安装 apbs, sudo apt install apbs 安装 gawk, sudo apt install gawk MD模拟好的文件 我们以研究蛋白小分子动态相互作用-III(蛋白配体…...

Kafka优化篇-压测和性能调优

简介 Kafka的配置详尽、复杂&#xff0c;想要进行全面的性能调优需要掌握大量信息&#xff0c;这里只记录一下我在日常工作使用中走过的坑和经验来对kafka集群进行优化常用的几点。 Kafka性能调优和参数调优 性能调优 JVM的优化 java相关系统自然离不开JVM的优化。首先想到…...

MinIo-SDK

3.2.5 SDK 3.2.5.1上传文件 MinIO提供多个语言版本SDK的支持&#xff0c;下边找到java版本的文档&#xff1a; 地址&#xff1a;https://docs.min.io/docs/java-client-quickstart-guide.html 最低需求Java 1.8或更高版本: maven依赖如下&#xff1a; XML<dependency&g…...

系统分析师真题2018试卷相关概念一

面向对象的基本概念: 对象的三要素为:属性(数据)、方法(操作)、对象ID(标识)UML2.0包括14种图: 类图(class diagram):类图描述一组类、接口、协作和他们之间的关系。在OO系统的建模中,最常见的图就是类图。类图给出了系统的静态设计图,活动类的类图给出了系统的静…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

【C++从零实现Json-Rpc框架】第六弹 —— 服务端模块划分

一、项目背景回顾 前五弹完成了Json-Rpc协议解析、请求处理、客户端调用等基础模块搭建。 本弹重点聚焦于服务端的模块划分与架构设计&#xff0c;提升代码结构的可维护性与扩展性。 二、服务端模块设计目标 高内聚低耦合&#xff1a;各模块职责清晰&#xff0c;便于独立开发…...

ArcGIS Pro制作水平横向图例+多级标注

今天介绍下载ArcGIS Pro中如何设置水平横向图例。 之前我们介绍了ArcGIS的横向图例制作&#xff1a;ArcGIS横向、多列图例、顺序重排、符号居中、批量更改图例符号等等&#xff08;ArcGIS出图图例8大技巧&#xff09;&#xff0c;那这次我们看看ArcGIS Pro如何更加快捷的操作。…...

在树莓派上添加音频输入设备的几种方法

在树莓派上添加音频输入设备可以通过以下步骤完成&#xff0c;具体方法取决于设备类型&#xff08;如USB麦克风、3.5mm接口麦克风或HDMI音频输入&#xff09;。以下是详细指南&#xff1a; 1. 连接音频输入设备 USB麦克风/声卡&#xff1a;直接插入树莓派的USB接口。3.5mm麦克…...

上位机开发过程中的设计模式体会(1):工厂方法模式、单例模式和生成器模式

简介 在我的 QT/C 开发工作中&#xff0c;合理运用设计模式极大地提高了代码的可维护性和可扩展性。本文将分享我在实际项目中应用的三种创造型模式&#xff1a;工厂方法模式、单例模式和生成器模式。 1. 工厂模式 (Factory Pattern) 应用场景 在我的 QT 项目中曾经有一个需…...

CppCon 2015 学习:REFLECTION TECHNIQUES IN C++

关于 Reflection&#xff08;反射&#xff09; 这个概念&#xff0c;总结一下&#xff1a; Reflection&#xff08;反射&#xff09;是什么&#xff1f; 反射是对类型的自我检查能力&#xff08;Introspection&#xff09; 可以查看类的成员变量、成员函数等信息。反射允许枚…...

qt+vs Generated File下的moc_和ui_文件丢失导致 error LNK2001

qt 5.9.7 vs2013 qt add-in 2.3.2 起因是添加一个新的控件类&#xff0c;直接把源文件拖进VS的项目里&#xff0c;然后VS卡住十秒&#xff0c;然后编译就报一堆 error LNK2001 一看项目的Generated Files下的moc_和ui_文件丢失了一部分&#xff0c;导致编译的时候找不到了。因…...

Python第七周作业

Python第七周作业 文章目录 Python第七周作业 1.使用open以只读模式打开文件data.txt&#xff0c;并逐行打印内容 2.使用pathlib模块获取当前脚本的绝对路径&#xff0c;并创建logs目录&#xff08;若不存在&#xff09; 3.递归遍历目录data&#xff0c;输出所有.csv文件的路径…...

C++中vector类型的介绍和使用

文章目录 一、vector 类型的简介1.1 基本介绍1.2 常见用法示例1.3 常见成员函数简表 二、vector 数据的插入2.1 push_back() —— 在尾部插入一个元素2.2 emplace_back() —— 在尾部“就地”构造对象2.3 insert() —— 在任意位置插入一个或多个元素2.4 emplace() —— 在任意…...

Vue3学习(接口,泛型,自定义类型,v-for,props)

一&#xff0c;前言 继续学习 二&#xff0c;TS接口泛型自定义类型 1.接口 TypeScript 接口&#xff08;Interface&#xff09;是一种定义对象形状的强大工具&#xff0c;它可以描述对象必须包含的属性、方法和它们的类型。接口不会被编译成 JavaScript 代码&#xff0c;仅…...