React之受控组件和非受控组件以及高阶组件

news2024/11/16 2:29:52

一、受控组件

受控组件,简单来讲,就是受我们控制的组件,组件的状态全程响应外部数据

举个简单的例子:

class TestComponent extends React.Component {
  constructor (props) {
    super(props);
    this.state = { username: 'lindaidai' };
  }
  render () {
    return <input name="username" value={this.state.username} />
  }
}

这时候当我们在输入框输入内容的时候,会发现输入的内容并无法显示出来,也就是input标签是一个可读的状态

这是因为valuethis.state.username所控制住。当用户输入新的内容时,this.state.username并不会自动更新,这样的话input内的内容也就不会变了

如果想要解除被控制,可以为input标签设置onChange事件,输入的时候触发事件函数,在函数内部实现state的更新,从而导致input框的内容页发现改变

因此,受控组件我们一般需要初始状态和一个状态更新事件函数

二、非受控组件

非受控组件,简单来讲,就是不受我们控制的组件

一般情况是在初始化的时候接受外部数据,然后自己在内部存储其自身状态

当需要时,可以使用ref 查询 DOM并查找其当前值,如下:

import React, { Component } from 'react';

export class UnControll extends Component {
  constructor (props) {
    super(props);
    this.inputRef = React.createRef();
  }
  handleSubmit = (e) => {
    console.log('我们可以获得input内的值为', this.inputRef.current.value);
    e.preventDefault();
  }
  render () {
    return (
      <form onSubmit={e => this.handleSubmit(e)}>
        <input defaultValue="lindaidai" ref={this.inputRef} />
        <input type="submit" value="提交" />
      </form>
    )
  }
}

三、高阶组件

1、是什么

高阶函数(Higher-order function),至少满足下列一个条件的函数

  • 接受一个或多个函数作为输入
  • 输出一个函数

React中,高阶组件即接受一个或多个组件作为参数并且返回一个组件,本质也就是一个函数,并不是一个组件

const EnhancedComponent = highOrderComponent(WrappedComponent);

上述代码中,该函数接受一个组件WrappedComponent作为参数,返回加工过的新组件EnhancedComponent

高阶组件的这种实现方式,本质上是一个装饰者设计模式

2、如何编写

最基本的高阶组件的编写模板如下:

import React, { Component } from 'react';

export default (WrappedComponent) => {
  return class EnhancedComponent extends Component {
    // do something
    render() {
      return <WrappedComponent />;
    }
  }
}

通过对传入的原始组件 WrappedComponent 做一些你想要的操作(比如操作 props,提取 state,给原始组件包裹其他元素等),从而加工出想要的组件 EnhancedComponent

把通用的逻辑放在高阶组件中,对组件实现一致的处理,从而实现代码的复用

所以,高阶组件的主要功能是封装并分离组件的通用逻辑,让通用逻辑在组件间更好地被复用

但在使用高阶组件的同时,一般遵循一些约定,如下:

  • props 保持一致
  • 你不能在函数式(无状态)组件上使用 ref 属性,因为它没有实例
  • 不要以任何方式改变原始组件 WrappedComponent
  • 透传不相关 props 属性给被包裹的组件 WrappedComponent
  • 不要再 render() 方法中使用高阶组件
  • 使用 compose 组合高阶组件
  • 包装显示名字以便于调试

这里需要注意的是,高阶组件可以传递所有的props,但是不能传递ref

如果向一个高阶组件添加refe引用,那么ref 指向的是最外层容器组件实例的,而不是被包裹的组件,如果需要传递refs的话,则使用React.forwardRef,如下:

function withLogging(WrappedComponent) {
    class Enhance extends WrappedComponent {
        componentWillReceiveProps() {
            console.log('Current props', this.props);
            console.log('Next props', nextProps);
        }
        render() {
            const {forwardedRef, ...rest} = this.props;
            // 把 forwardedRef 赋值给 ref
            return <WrappedComponent {...rest} ref={forwardedRef} />;
        }
    };

    // React.forwardRef 方法会传入 props 和 ref 两个参数给其回调函数
    // 所以这边的 ref 是由 React.forwardRef 提供的
    function forwardRef(props, ref) {
        return <Enhance {...props} forwardRef={ref} />
    }

    return React.forwardRef(forwardRef);
}
const EnhancedComponent = withLogging(SomeComponent);

四、应用场景 

1、受控组件与非受控组件

大部分时候推荐使用受控组件来实现表单,因为在受控组件中,表单数据由React组件负责处理

如果选择非受控组件的话,控制能力较弱,表单数据就由DOM本身处理,但更加方便快捷,代码量少

针对两者的区别,其应用场景如下图所示:

2、高阶组件 

通过上面的了解,高阶组件能够提高代码的复用性和灵活性,在实际应用中,常常用于与核心业务无关但又在多个模块使用的功能,如权限控制、日志记录、数据校验、异常处理、统计上报等

举个例子,存在一个组件,需要从缓存中获取数据,然后渲染。一般情况,我们会如下编写:

import React, { Component } from 'react'

class MyComponent extends Component {

  componentWillMount() {
      let data = localStorage.getItem('data');
      this.setState({data});
  }
  
  render() {
    return <div>{this.state.data}</div>
  }
}

上述代码当然可以实现该功能,但是如果还有其他组件也有类似功能的时候,每个组件都需要重复写componentWillMount中的代码,这明显是冗杂的

下面就可以通过高价组件来进行改写,如下:

import React, { Component } from 'react'

function withPersistentData(WrappedComponent) {
  return class extends Component {
    componentWillMount() {
      let data = localStorage.getItem('data');
        this.setState({data});
    }
    
    render() {
      // 通过{...this.props} 把传递给当前组件的属性继续传递给被包装的组件WrappedComponent
      return <WrappedComponent data={this.state.data} {...this.props} />
    }
  }
}

class MyComponent2 extends Component {  
  render() {
    return <div>{this.props.data}</div>
  }
}

const MyComponentWithPersistentData = withPersistentData(MyComponent2)

再比如组件渲染性能监控,如下:

class Home extends React.Component {
    render() {
        return (<h1>Hello World.</h1>);
    }
}
function withTiming(WrappedComponent) {
    return class extends WrappedComponent {
        constructor(props) {
            super(props);
            this.start = 0;
            this.end = 0;
        }
        componentWillMount() {
            super.componentWillMount && super.componentWillMount();
            this.start = Date.now();
        }
        componentDidMount() {
            super.componentDidMount && super.componentDidMount();
            this.end = Date.now();
            console.log(`${WrappedComponent.name} 组件渲染时间为 ${this.end - this.start} ms`);
        }
        render() {
            return super.render();
        }
    };
}

export default withTiming(Home);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1106894.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

最新百度统计配置图文教程,获取siteId、百度统计AccessToken、百度统计代码教程

一、前言 很多网友开发者都不知道百度统计siteId、百度统计token怎么获取&#xff0c;在网上找的教程都是几年前老的教程&#xff0c;因此给大家出一期详细百度统计siteId、百度统计token、百度统计代码获取详细步骤教程。 二、登录到百度统计 1.1 登录到百度统计官网 使用…

零基础学习HTML5(列表、表格、表单)

01-列表 作用&#xff1a;布局内容排列整齐的区域。 列表分类&#xff1a;无序列表、有序列表、定义列表。 无序列表 作用&#xff1a;布局排列整齐的不需要规定顺序的区域。 标签&#xff1a;ul 嵌套 li&#xff0c;ul 是无序列表&#xff0c;li 是列表条目。 <ul>…

2506. 统计相似字符串对的数目

2506. 统计相似字符串对的数目 js代码&#xff1a; /*** param {string[]} words* return {number}*/ var similarPairs function (words) {// 将字符串数组的每一项去重排序words words.map(item > [...new Set(item)].sort().join())let res 0for (let i 0; i < w…

lvgl模拟器添加图片,编译提示无法解析的外部符号

目录 一、1. v_img_set_src(obj, &img_cogwheel_argb);2. 二、1.2. 一、 1. v_img_set_src(obj, &img_cogwheel_argb); 编译一下&#xff0c;报以下错误 错误原因是img_cogwheel_argb.c 文件中的变量img_cogwheel_argb定义按C编译 const lv_img_dsc_t img_cogwhee…

docker入门加实战—部署Java和前端项目

docker入门加实战—部署Java和前端项目 部署之前&#xff0c;先删除nginx&#xff0c;和自己创建的dd两个容器&#xff1a; docker rm -f nginx dd部署Java项目 作为演示&#xff0c;我们的Java项目比较简单&#xff0c;提供了一个接口&#xff1a; 配置文件连接docker里的m…

自动切割短视频的软件推荐,一键生成1000条短视频,支持六大主流平台矩阵分发,快来免费试用

经过小编的多方测评&#xff0c;今天给大家推荐一款性价比、好评率、专业性全都超高的软件——超级编导批量剪辑软件&#xff0c;更重要的是这款软件支持免费试用&#xff0c;一起来看看超级编导如何帮助大家自动分割视频的吧。 复制视频链接&#xff0c;一键上传视频素材后&am…

JAVA基础(JAVA SE)学习笔记(四)IDEA安装、使用、设置、断点、乱码汇总

前言 1. 学习视频&#xff1a; 尚硅谷Java零基础全套视频教程(宋红康2023版&#xff0c;java入门自学必备)_哔哩哔哩_bilibili 2023最新Java学习路线 - 哔哩哔哩 正文 JAVA基础&#xff08;JAVA SE&#xff09;学习笔记&#xff08;一&#xff09;JAVA学习路线、行业了解…

【复盘】记录一次数据库连接资源占用完毕

背景 因为历史原因项目使用的是JDBC原始SQL&#xff0c;然后进行拉去三方数据进行解析分析。跑了一会之后发现影响到了线上业务&#xff0c;连接错误。 一查看其实就是刚才跑的定时导致的&#xff0c;分析了下没有及时释放数据库连接。导致资源耗尽。数据库异常。 所以这里其实…

大数据之Hudi数据湖_基本概念_文件布局_文件管理 基本概念_索引_的原理_索引选项_全局索引与非全局索引---大数据之Hudi数据湖工作笔记0007

这里对于hudi中有两种表,一种是MOR表,这个是hudi表,一种是COW表, MOR表会产生日志,因为会有增删改的日子对数据的,然后COW是没有日志的,COW是copy on write 的意思.是复制的数据所以不会牵扯到该删的操作. 这里因为hudi有多版本控制,所以这里就有了合并日志和基本文件的操作,…

掌握C++魔法:深入解析类与对象(上篇)

W...Y的主页 &#x1f60a; 代码仓库分享 &#x1f495; &#x1f354;前言&#xff1a; 之前我们学习了从C语言转到C后我们需要知道的一些关键改动与变化。今天我们就要学习C独有的类与对象。在谈论类与对象之前我们先说一下什么是面向对象的C&#xff0c;什么是面向过程的C语…

【网络】计算机网络基础概念入门

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_Linux,大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341;&#x1fa81;&#x1f341;&#x1fa81;…

【安全】网络安全态势感知

一、态势感知简介 如果你对网络安全入门感兴趣&#xff0c;那么你需要的话可以点击这里&#x1f449;【入门&进阶全套282G学习资源包免费分享&#xff01;】 1.概念 态势感知是一种基于环境的、动态、整体地洞悉安全风险的能力&#xff0c;是以 安全大数据 为基础&#…

【MyBatisPlus】快速入门、常用注解、常用配置

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 MyBatisPlus 一、快速入门1.1 引入MyBatisP…

YOLOv7改进:引入GSConv+Slim Neck,提升小目标检测精度

💡💡💡本文属于原创独家改进 引入了一种新方法 GSConv 来代替 SC 操作。该方法使卷积计算的输出尽可能接近 SC,同时降低计算成本; 提供了一种新的设计范式,即带有标准 Backbone 的 Slim-Neck 设计; GSConv+Slim Neck | 亲测在多个数据集实现暴力涨点; 收录: YO…

分布式内存计算Spark环境部署与分布式内存计算Flink环境部署

目录 分布式内存计算Spark环境部署 1. 简介 2. 安装 2.1【node1执行】下载并解压 2.2【node1执行】修改配置文件名称 2.3【node1执行】修改配置文件&#xff0c;spark-env.sh 2.4 【node1执行】修改配置文件&#xff0c;slaves 2.5【node1执行】分发 2.6【node2、no…

酒店报修管理系统哪家好?设备巡检系统对酒店运营有什么帮助?

酒店报修管理系统是一款关键的软件工具&#xff0c;可以帮助酒店员工和客户更有效地管理酒店的各项运营活动。下面我们将通过问答形式&#xff0c;深入探讨酒店管理系统的特性和功效&#xff0c;以便了解它如何提升酒店员工的工作效率&#xff0c;以及如何将酒店的各个部门和员…

正方形(Squares, ACM/ICPC World Finals 1990, UVa201)rust解法

有n行n列&#xff08;2≤n≤9&#xff09;的小黑点&#xff0c;还有m条线段连接其中的一些黑点。统计这些线段连成了多少个正方形&#xff08;每种边长分别统计&#xff09;。 行从上到下编号为1&#xff5e;n&#xff0c;列从左到右编号为1&#xff5e;n。边用H i j和V i j表示…

软设上午题错题知识点5

软设上午题错题知识点5 1、在ASP的内置对象中。能修改cookie中的值的是response&#xff0c;它还可以创建cookie&#xff0c;而request可以访问cookie中的参数。 2、抽象工厂&#xff08;AbstractFactory&#xff09;模式提供一个创建一系列相关或相互依赖对象的接口&#xf…

JUC并发编程——JMM详解(基于狂神说得到学习笔记)

JMM 什么是JMM (Java Memory Model) 参考文献JMM概述-CSDN博客 内存模型可以理解为在特定的操作协议下&#xff0c;对特定的内存或者高速缓存进行读写访问的过程抽象描述&#xff0c;不同架构下的物理机拥有不一样的内存模型&#xff0c;Java虚拟机是一个实现了跨平台的虚拟系…

基于springboot的高校科研管理系统(源码+调试+LW)

项目描述 临近学期结束&#xff0c;还是毕业设计&#xff0c;你还在做java程序网络编程&#xff0c;期末作业&#xff0c;老师的作业要求觉得大了吗?不知道毕业设计该怎么办?网页功能的数量是否太多?没有合适的类型或系统?等等。这里根据你想解决的问题&#xff0c;今天给…