React自定义Componment和State深层次理解-07

本节主要从底层原理上分析下React开发相关的内容和注意事项,本节会围绕使用展开,而非源码讲解。

Componment详解

什么是组件

在 MVVM架构出现之前,组件主要分为两种。

  • 狭义上的组件,又称为 UI 组件,比如 Tabs 组件、Dropdown 组件。组件主要围绕在交互动作上的抽象,针对这些交互动作,利用 JavaScript 操作 DOM 结构或 style
    样式来控制。这样的逻辑一旦复杂,就存在大量的 DOM 操作,开发及维护成本相当高。
  • 广义上的组件,即带有业务含义和数据的 UI 组件组合。这类组件不仅有交互动作,更重 要的是有数据与界面之间的交互。然而,这类组件往往有较大的争议。在规模较大的场景下,我们更倾向于采用分层的思想去处理。

React 的本质核心关心元素的构成, React 组件也可理解为组件元素。组件元素被描述成纯粹的 JSON 对象,意味着可以使用方法或是类来构建。React 组件基本上由 3 个部分组成:属性(props)、状态(state)以及生命周期方法。

组件的生命周期

  • 下图是一个详细的数据流图:
    在这里插入图片描述
  • 对上图进行不同阶段的分解后,不同操作执行过程如下表所示:
First RenderUnmoutPropes changeState change
getDefaultPropscomponentWillUnMountcomponentWillReceivePropsshouldComponentUpdate
getInitialStaterendershouldComponentUpdatecomponentWillUpdate
componentWillMountgetInitialStatecomponentWillUpdaterender
rendercomponentWillMountrendercomponentDidUpdate
componentDidMountcomponentDidMountcomponentDidUpdate
  • 原码方法详解如下:(需要注意,不同版本的React方法可能不太一样)
/*组件再次渲染时,在render()渲染前调用,即props和state发生变化时会触发此方法*/
componentWillUpdate: function () {
},/*组件再次渲染时,在render()渲染后调用*/
componentDidUpdate: function () {
},/*在新节点插入DOM结构之前调用*/
componentWillMount: function () {
},/*在新节点插入DOM结构之后调用*/
componentDidMount: function () {
},/*在组件从DOM中移除时调用*/
componentWillUnmount: function () {
},/*在componentWillUpdate()之前调用,用来决定组件是否调用render()来更新,返回true和false*/
shouldComponentUpdate(nextProps, nextState){
}

在这里插入图片描述

创建组件的步骤

  • 以下是一个指引,在使用熟练之外基本不用参考如下图流程。
    在这里插入图片描述
  • 在构造大型组件时一是要考虑复用、二是要考虑其可跳跃性,所以一般会以树状结构构建,详细的例子可参考 将 UI 视为树
    在这里插入图片描述

用分离模式来设计组件

虽然可以把一个组件的所有代码写在一个.js文件中,但这种方法的复用度不是太好,所以一般要设计大型组件时一般会采用分离设计:数据+UI数据+UI+包装器,这种设计方式主要依赖了React的:

  1. props这种可以共享数据的机制;
  2. 、组件调用时可以传递子元素的属性(是一个children数组)。
    比如下例:

定义UI组件

这里只关注样式,没有状态数据

import React from 'react'const Geolocation = ({ latitude, longitude }) => (<div><div>Latitude: {latitude}</div><div>Longitude: {longitude}</div></div>
)Geolocation.propTypes = {latitude: React.PropTypes.number,longitude: React.PropTypes.number,
}export default Geolocation

定义UI容器

包装了UI组件,同时所有的状态全在这里进行处理

import React from 'react'
import Geolocation from './geolocation'class GeolocationContainer extends React.Component {constructor(props) {super(props)this.state = {latitude: null,longitude: null,}this.handleSuccess = this.handleSuccess.bind(this)}handleSuccess({ coords }) {this.setState({latitude: coords.latitude,longitude: coords.longitude,})}render() {return ( //此处包装<Geolocation {...this.state} />)}
}export default GeolocationContainer

保持组件的纯粹

React 便围绕着这个概念进行设计。React 假设你编写的所有组件都是纯函数。也就是说,对于相同的输入,你所编写的 React 组件必须总是返回相同的 JSX。简单理解一下就是上面所说的UI和操作分离的情况。比如下面的例子:

function Cup() {// Bad:正在更改预先存在的变量!,最好把guest做为Cup的一个参数guest = guest + 1;return <h2>Tea cup for guest #{guest}</h2>;
}export default function TeaSet() {return (<><Cup /><Cup /><Cup /></>);
}

这种作法有助于:

  • 组件可以在不同的环境下运行 — 例如,在服务器上!由于它们针对相同的输入,总是返回相同的结果,因此一个组件可以满足多个用户请求。
  • 可以为那些输入未更改的组件来 跳过渲染,以提高性能。这是安全的做法,因为纯函数总是返回相同的结果,所以可以安全地缓存它们。
  • 如果在渲染深层组件树的过程中,某些数据发生了变化,React 可以重新开始渲染,而不会浪费时间完成过时的渲染。纯粹性使得它随时可以安全地停止计算。

组件渲染的时机

有两种原因会导致组件的渲染:

  1. 组件的 初次渲染。在进行初次渲染时, React 会调用根组件。
  2. 组件(或者其祖先之一)的 状态发生了改变。对于后续的渲染, React 会调用内部状态更新触发了渲染的函数组件。

这个过程是递归的:如果更新后的组件会返回某个另外的组件,那么 React 接下来就会渲染 那个 组件,而如果那个组件又返回了某个组件,那么 React 接下来就会渲染 那个 组件,以此类推。这个过程会持续下去,直到没有更多的嵌套组件并且 React 确切知道哪些东西应该显示到屏幕上为止。

基于以上,也是为什么要保持组件纯粹的原因了,因为这关乎性能。

State详解

这东西到底干啥用的呢,本质上React也是一个MVVM的实现(核心是一个有状态的组件),虽然可以通过传统的方式来实现数据改变时的UI样式,但会比较麻烦,所以React给每个组件加了一个state功能,通过state来实现数据和展现的互动,其原理简单理解如下:
在这里插入图片描述

state 机制目的是代替原有的props机制实现数据和视图的绑定。setState(),方法可接受一个Object参数,内部会把此参数和原state数据进行合并。

setState()

语法格式:setState({}, callBack)

一般在使用React开发组件时,建议选择受控组件开发,然后通过控制state进而控制render()方法的调用,用这种方式来取代非受控组件的开发模式。

比如:在下例中input 绑定一个 change 事件,每当表单的状态发生变化时,都会被写入到组件的 state 中,这种组件在 React 中被称为受控组件(controlled component)。在受控组件中,React 通过这种方式消除了组件的局部状态,使得应用的整个状态更加可控, React 受控组件更新 state 的流程:

  1. 可以通过在初始 state 中设置表单的默认值。
  2. 每当表单的值发生变化时,调用 onChange 事件处理器。
  3. 事件处理器通过合成事件对象 e 拿到改变后的状态,并更新应用的 state。
  4. setState 触发视图的重新渲染,完成表单组件值的更新。
class App extends React.Component {constructor(props) {super(props);this.handleInputChange = this.handleInputChange.bind(this);this.state = {inputVal: 'male', //默认值};}handleInputChange(e) {this.setState({inputVal: e.target.value,});}render() {const { inputVal} = this.state;return (<div><input type="radio" value="male" checked={inputVal === 'male'} onChange={this.handleInputChange}/></div>);}}

其底层原理是,在 React 内部,为每个组件保存了一个数组,其中每一项都是一个 state 对。它维护当前 state 对的索引值,在渲染之前将其设置为 “0”。每次调用 useState 时,React 都会为你提供一个 state 对并增加索引值。

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

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

相关文章

Java计算日期相差天数的几种方法

Java计算日期相差天数的几种方法 &#x1f5d3;️ Java计算日期相差天数的几种方法摘要引言一、使用java.util.Date和java.util.Calendar&#x1f4c5;1. 使用java.util.Date示例代码 2. 使用java.util.Calendar示例代码 二、使用java.time.LocalDate&#x1f4c6;示例代码 三、…

微信小程序文本框输入显示已经输入的字数

我们遇到这样的需求&#xff0c;就是微信小程序的输入框下面需要显示输入的字数&#xff1a; 我们通常会使用bindinput事件&#xff0c;让显示的字数等于value的长度&#xff0c;看下面的图&#xff1a; 但在实践中&#xff0c;真机测试中&#xff0c;我们会发现以下问题: 这个…

IP编址、进制转换、IP地址分类、变长子网掩码VLSM、无类域间路由CIDR

前言 网络层位于数据链路层与传输层之间。网络层中包含了许多协议&#xff0c;其中最为重要的协议就是IP协议。网络层提供了IP路由功能。理解IP路由除了要熟悉IP协议的工作机制之外&#xff0c;还必须理解IP编址以及如何合理地使用IP地址来设计网络。 IP编址 每个网段上都有两…

Java的类路径究竟是什么?

回答 问了chatgpt这个问题&#xff0c;首先类路径的定义是&#xff1a; 是指一组路径&#xff0c;这些路径告诉Java虚拟机&#xff08;JVM&#xff09;和类加载器在哪里可以找到应用程序所需的类和资源文件。说白了就是在运行java程序的时候需要先将java源代码编译成class文件…

基础IO用户缓冲区 、inode、硬软链接【Linux】

文章目录 用户缓冲区磁盘磁盘分区EXT2文件系统的存储方案 inode软链接硬链接 用户缓冲区 代码一&#xff1a; 1 #include<stdio.h>2 #include<unistd.h>3 #include<string.h> 4 int main()5 {6 const char * fstr &…

基于FIDO2和USBKEY硬件的SSH认证

在 8.2&#xff08;最新为 8.3&#xff09;版本中&#xff0c;OpenSSH 提供了对 FIDO 和 UAF 的支持。从此用户就可以用硬件 USBKEY 证书进行 SSH 原生认证。这样可以实现简捷、有效和安全的 SSH 认证。本文我们就就少一下 FIDO2 以及 OpenSSH 对其的支持&#xff0c;并尝试一下…

【调试笔记-20240521-Linux-编译 QEMU/x86_64 可运行的 OpenWrt 固件】

调试笔记-系列文章目录 调试笔记-20240521-Linux-编译 QEMU/x86_64 可运行的 OpenWrt 固件 文章目录 调试笔记-系列文章目录调试笔记-20240521-Linux-编译 QEMU/x86_64 可运行的 OpenWrt 固件 前言一、调试环境操作系统&#xff1a;Ubuntu 22.04.4 LTS编译环境调试目标 二、调…

日志的介绍及简单实现

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 日志是什么&#xff1f; 为什么需要日志&#xff1f; 实现一个简单日志 时间戳 clock_gettime time & localtime 可变模板参数(使用C语言)&#xff0c;va_start & va_end & vsprintf 宏 __LINE__…

Digital Image Processing System(DIPS)

数字图像处理系统 Digital Image Processing System&#xff08;DIPS&#xff09; 早前版本&#xff1a; ​​​​​​​DIPS_YTPC OCR-CSDN博客

数据结构和算法|排序算法系列(二)|冒泡排序

首先需要你对排序算法的评价维度和一个理想排序算法应该是什么样的有一个基本的认知&#xff1a; 《Hello算法之排序算法》 主要内容来自&#xff1a;Hello算法11.3 冒泡排序 我觉得冒泡排序非常有意思&#xff0c;也非常简单&#xff0c;就是不停地交换相邻的元素即可&#…

ElasticSearch插件版本与ES版本不对应的解决方案

一、背景 最近需要给es安装ik、hanlp分词器和ingest-attachment管道&#xff0c;服务器已有的es版本为8.5.3&#xff08;似乎太新了&#xff09;&#xff0c;hanlp和ingest-attachment都没有这么高的版本&#xff0c;因此只能下载相对老的版本&#xff0c;然后自己修改配置文件…

安全设计 | 安全设计不得马虎!微软STRIDE威胁建模方法让你事半功倍,快速发现应用安全隐患!

STRIDE威胁建模方法最早发表于2006年11月的《MSDN杂志》&#xff0c;作者是微软的工程师Shawn Hernan、Scott Lambert 、Tomasz Ostwald 和 Adam Shostack。那我们为什么要进行威胁建模&#xff1f; 如何使用数据流图对系统进行威胁建模&#xff1f;如何减轻威胁&#xff1f;接…

java项目之桂林旅游景点导游平台源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的桂林旅游景点导游平台。 项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 桂林旅游景点导游…

mysql5.5版本安装过程

mysql是关系型数据库的管理系统 将安装包放在 c盘根目录 名称为mysql 在该路径下cmd进入命令执行窗口 出现此页面说明安装成功 需要修改配置文件内容 将my-medium.ini 复制粘贴并改名为 my.ini 并添加如下内容 改好之后在mysql目录下cmd进入命令执行窗口 切换到cd bin …

Java实现图书系统

首先实现一个图书管理系统,我们要知道有哪些元素? 1.用户分成为管理员和普通用户 2.书:书架 书 3.操作的是: 书架 目录 第一步:建包 第二步:搭建框架 首先:完成book中的方法 其次:完成BookList 然后:完成管理员界面和普通用户界面 最后:Main 第三步:细分方法 1.退…

Spring—Spring配置文件概念及应用(实现一个图形验证码)

文章目录 配置文件配置文件作用配置文件的格式配置文件优先级说明配置文件书写代码的格式yml文件代码的格式 Value注解 properties 缺点分析properties VS yml实现一个验证码程序 配置文件 配置文件作用 整个项目的重要信息我们都会配置在配置文件中&#xff0c;比如说我们数…

视频拼接融合产品的产品与架构设计(四)分布式GPU运算合并单元

上一篇如下 视频拼接融合产品的产品与架构设计(三&#xff09;内存和显存单元数据迁移 视频合并单元说明 对下面这张图做些说明&#xff0c;视频接入是比较常见&#xff0c;可以说是普通&#xff0c;但是做到接入后随即进行比较重的算法运算&#xff0c;这个在视频领域并不多…

软件项目详细设计说明书实际项目参考(word原件下载及全套软件资料包)

系统详细设计说明书案例&#xff08;直接套用&#xff09; 1.系统总体设计 2.性能设计 3.系统功能模块详细设计 4.数据库设计 5.接口设计 6.系统出错处理设计 7.系统处理规定 软件开发全文档下载&#xff08;下面链接或者本文末个人名片直接获取)&#xff1a;软件开发全套资料-…

C++ 常用UI库

AWTK github gitee doc scons 类似RT-Thread element github C Cross platfrom C GUI libraries&#xff0c;QT可替代方案。调试包 SDL GUI cegui 创作不易&#xff0c; 小小的支持一下吧&#xff01;

泛型...

定义&#xff1a;在编译过程中约束操作的数据类型。&#xff08;统一数据类型&#xff09; 格式&#xff1a;<数据类型> 泛型中不能写基本数据类型。 泛型类 在一个类中&#xff0c;某个变量的数据类型不确定时&#xff0c;可以定义带有泛型的类。 泛型的底层是Obje…