一、React 是什么
React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作“组件”。
1.1、React的优点
-
采用组件化模式,声明式编程( react是面向数据编程,不需要直接去控制dom,你只要把数据操作好,react自己会去帮你操作dom,可以节省很多操作dom的代码。这就是声明式开发),提高开发效率与组件复用率;
- 在 React Native 中可以使用 React 语法进行移动端开发;
-
通过虚拟DOM + Diffing算法,最大限度的减少与DOM的交互,速度很快;
-
使用JSX,代码可读性很好;
-
React 可以与已有的库或者框架很好的配合;
-
使用 React 构建组件使代码更加容易得到复用,可以很好的应用在大项目的开发过程中;
-
其单向数据流减少了重复的代码,轻松实现数据绑定。
1.2、React的缺点
-
React 不适合单独做一个完整的框架,做大型项目需要和其他框架组合使用
-
React 的库非常庞大,新手很难理解需要花费一定的时间,使用内联模板和JSX,使编码变得复杂
1.3、React 与 Vue 的区别
理念差异:
从设计理念上来说,vue更像是一种模板引擎。所谓模板引擎就是在静态模板上动态替换 Js 变量,最终渲染出页面。一个vue文件中,有html、css、js,放在一起。很直观,html 是静态模板,js 是动态变量。vue 在模板引擎的基础上加了很多 v 指令,大大简化了开发。但是当 js 逻辑很复杂的时候,状态管理变得很麻烦。
而对于React来说,React受函数式编程的影响,将 html 视为数据映射的结果,一个数据映射一个 html ,组合起来就是一个完整的页面DOM树。这则是区别于“ 模板思维”的“映射思维”。这是React与Vue最核心的差异。
对于 vue 来说,html 是首位,vue 中的 html 模板已经算是一个近乎完整的页面,只不过有几个变量无法确定,再把 js 加上去就好。而对于 React 来说,Js 是首位,有 Js 才有 html,Js 是因,html 是果。
共同点:
虚拟Dom:改变真实的DOM状态远比改变一个JavaScript对象的花销要大得多。 Virtual DOM是一个映射真实 DOM 的 JavaScript 对象,如果需要改变任何元素的状态,那么是先在 Virtual DOM 上进行改变,而不是直接改变真实的 DOM。当有变化产生时,一个新的 Virtual DOM 对象会被创建并计算新旧 Virtual DOM 之间的差别。之后这些差别会应用在真实的 DOM上。这极大的提高了性能。
组件化:vue 和 react 都建议将应用拆分成多个组件,每个组件负责不同的工作,组件之间通过特殊的方式相互关联。使应用的结构变得清晰,也有利于组件复用。
区别:
Vue 建议使用 html 模板进行编写,而 React 则使用了Javascript 的扩展语法 —— JSX,赋予了开发者许多变成能力。
React 应用中的状态是(React)关键的概念。也有一些配套框架被设计为管理一个大的 state 对象,如 Redux。此外,state 对象在 React 应用中是不可变的,意味着它不能被直接改变(这也许不一定正确)在 React 中你需要使用 setState() 方法去更新状态。
在 vue中,数据由 data 属性在 Vue 对象中进行管理。data 参数就是应用中数据的保存者。 对于管理大型应用中的状态这一话题而言,Vue 解决方案适用于小型应用,但对于对于大型应用而言不太适合。
第一标题的原文链接:https://blog.csdn.net/qq_45643079/article/details/119914443
二、React 的实现
第一次渲染数据的时候,会在Virtual-Dom里面进行比较,如果没有找到相同 DOM 就会创建一个新的虚拟DOM,然后就渲染到页面真实 DOM 重排页面元素,如果对比有相同虚拟DOM 就会复用该虚拟DOM,页面元素不会重排。
原本数组里面有2条数据,展示后虚拟 DOM 就会创建这两个数据<li>的虚拟DOM ,此时添加一条新的数据,这时候数组就会有三条数据,前面两条数据在第一次对比的时候就已经创建虚拟DOM了,前两条数据对比相同就不会渲染,而新添加的第三条数据,对比内存没有相对应的虚拟DOM,则创建新的虚拟DOM ,再重新渲染到页面上!
2.0、创建 react 项目
2.0.1、使用脚手架创建
创建命令:
npx create-react-app 项目名
2.0.2、使用 vite 创建
创建命令:
npm create vite@latest
选择 React !!!
2.0.3、react脚手架项目结构
public ---- 静态资源文件夹 favicon.icon ------ 网站页签图标 index.html -------- 主页面 logo192.png ------- logo图 logo512.png ------- logo图 manifest.json ----- 应用加壳的配置文件 robots.txt -------- 爬虫协议文件 src ---- 源码文件夹 App.css -------- App组件的样式 App.js --------- App组件 App.test.js ---- 用于给App做测试 index.css ------ 样式 index.js ------- 入口文件 logo.svg ------- logo图 reportWebVitals.js --- 页面性能分析文件(需要web-vitals库的支持) setupTests.js ---- 组件单元测试的文件(需要jest-dom库的支持)
2.1、使用 react 输出 “ hello,react ” 案例
实现代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>hello-react</title> </head> <body> <!-- 容器 --> <div id="test"></div> <!-- 引用的时候,一定要注意先后顺序!!! --> <!-- react:react核心库 --> <script type="text/javascript" src="./js/react.development.js"></script> <!-- react-dom:用于支持react操作DOM元素 --> <script type="text/javascript" src="./js/react-dom.development.js"></script> <!-- babel:用于将jsx转换为js --> <script type="text/javascript" src="./js/babel.min.js"></script> <!-- 请注意!! 这里一定要写babel --> <script type="text/babel"> // 1、创建虚拟DOM const VDDM = <h1>hello,react</h1> /* 这里一定不要写单引号,因为不是字符串 */ // 2、渲染虚拟DOM到页面里,使用ReactDOM.render(虚拟DOM,容器); ReactDOM.render(VDDM,document.getElementById("test")); // 请注意,我想再这个容器里面再写一句话 // const VDDM2 = <h1>hello,react</h1> // ReactDOM.render(VDDM2,document.getElementById("test")); // 这个是失败的,因为它不是追加,而是覆盖 </script> </body> </html>
运行结果:
2.2、虚拟DOM 的两种创建方法,并使用多级层次结构
2.2.1、使用 jsx 来创建虚拟 DOM
实现代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> </head> <body> <!-- 容器 --> <div id="test"></div> <!-- 引用的时候,一定要注意先后顺序!!! --> <!-- react:react核心库 --> <script type="text/javascript" src="../js/react.development.js"></script> <!-- react-dom:用于支持react操作DOM元素 --> <script type="text/javascript" src="../js/react-dom.development.js"></script> <!-- babel:用于将jsx转换为js --> <script type="text/javascript" src="../js/babel.min.js"></script> <!-- 请注意!! 这里一定要写babel --> <script type="text/babel"> // 1、创建虚拟DOM const VDDM = ( <h1 id="title"> <span>hello,react</span> </h1> ) /* 这里一定不要写单引号,因为不是字符串 */ // 2、渲染虚拟DOM到页面里,使用ReactDOM.render(虚拟DOM,容器); ReactDOM.render(VDDM,document.getElementById("test")); </script> </body> </html>
2.2.2、使用 js 来创建虚拟 DOM
实现代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title></title> </head> <body> <!-- 容器 --> <div id="test"></div> <!-- 引用的时候,一定要注意先后顺序!!! --> <!-- react:react核心库 --> <script type="text/javascript" src="../js/react.development.js"></script> <!-- react-dom:用于支持react操作DOM元素 --> <script type="text/javascript" src="../js/react-dom.development.js"></script> <!-- 不需要引入 babel --> <!-- 请注意!! 这里改为javascipt --> <script type="text/javascript"> // 1、创建虚拟DOM,创建节点:React.createElement("标签名","标签属性","标签内容") const VDDM = React.createElement("h1",{id: "title",class: "titles"},React.createElement("span",{},"Hello,React")); // 2、渲染虚拟DOM到页面里,使用ReactDOM.render(虚拟DOM,容器); ReactDOM.render(VDDM,document.getElementById("test")); </script> </body> </html>
运行结果:
2.3、虚拟DOM与真实DOM
虚拟DOM:
const VDDM = ( <h1 id="title"> <span>hello,react</span> </h1> )真实DOM:
document.getElementById("test");关于虚拟DOM:
-
1.本质是Object类型的对象(是一般对象)
-
2.虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性。
-
3.虚拟DOM最终会被React转换为真实DOM,呈现在页面上。
-
4.它是运行在内存里面的。
2.4、jsx 概要
JSX 是 Javascript 的一种语法拓展
JSX是 JavaScript XML 简写,表示在 JavaScript 中编写XML格式代码(也就是HTML格式)
2.4.1、jsx的优点
-
声明式语法更加直观
-
与HTML结构相同
-
降低了学习成本、提升开发效率
注意:JSX 并不是标准的 JS 语法,是 JS 的语法扩展,浏览器默认是不识别的,脚手架中内置的 @babel/plugin-transform-react-jsx 包,用来解析该语法的!
2.4.2、jsx语法规则
1.定义虚拟DOM时,不要写引号;
2.标签中混入JS表达式时使用{};
3.样式的类名指定不要用class,要用className,属性名采用驼峰命名法 class -> className,
for -> htmlFor
4.内联样式,要用style={{ key:value }}的形式去写
5.虚拟DOM只有一个根标签,如果没有根节点,可以使用 <></>
(幽灵节点)替代
6.标签必须闭合(input、img标签)成对闭合或者自闭合都可以
7.标签首字母
(1)如果小写字母开头,则将改标签转为html中的同名元素,如果html中没有该标签对应的同名元素,则报错
(2)如果大写字母开头,react就去渲染对应的组件,如果组件没有定义,则报错
8.JSX支持多行(换行),如果需要换行,需使用()
包裹,防止bug出现
2.4.3、jsx的练习 — 动态展示列表数据
2.4.3.1、区分js语句(例如 if 判断、for 循环)与 js 表达式
1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
表达式栗子:
以下的表达式都可以用一个变量来接收它返回的值
(1)a // 这个可以是一个变量名
(2)a+b // 加法表达式
(3)demo(1) // 这个是函数调用表达式
(4)arr.map()
(5)function.test(){}
2.语句:控制代码走向,并没有返回值
语句的栗子:
(1)if(){}
(2)for(){}
(3)switch(){case: xxx}
2.4.3.2、代码实现
代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>1</title> </head> <body> <!-- 容器 --> <div id="test"></div> <!-- react:react核心库 --> <script type="text/javascript" src="../js/react.development.js"></script> <!-- react-dom:用于支持react操作DOM元素 --> <script type="text/javascript" src="../js/react-dom.development.js"></script> <!-- babel:用于将jsx转换为js --> <script type="text/javascript" src="../js/babel.min.js"></script> <script type="text/babel"> // 模拟后端传过来的数据 const data = ['Angular','React','Vue'] // 创建虚拟DOM const VDOM = ( <div> <h1>前端js框架列表</h1> <ul> { // 加工数组,key是虚拟DOM的唯一标识符 data.map((item,index)=>{ return <li key={index}>{item}</li> }) } </ul> </div> ) // 渲染 ReactDOM.render(VDOM,document.getElementById("test")) </script> </body> </html>
运行结果:
三、组件(Component)
如果我们将一个页面中所有的处理逻辑全部放在一起,处理起来就会变得非常复杂,而且不利于后续的管理以及扩展,但如果,我们将一个页面拆分成一个个小的功能块,每个功能块完成属于自己这部分独立的功能,那么之后整个页面的管理和维护就变得非常容易了。如果我们将一个个功能块拆分后,就可以像搭建积木一下来搭建我们的项目。它接受任意的入参(即 “props”),并返回用于描述页面展示内容的 React 元素。
-
理解:用来实现局部功能效果的代码和资源的集合(html / css / js / image 等等)
-
为什么要用组件: 一个界面的功能更复杂
-
作用:复用编码, 简化项目编码, 提高运行效率
3.1、使用 class 定义组件,叫类样式组件
使用 class 定义组件需要满足两个条件:
-
class 继承自 React.Component
-
class 内部必须定义 render 方法,rende r方法返回代表该组件 UI 的 React 元素
栗子如下:
使用脚手架新建一个简易BBS项目,在这个项目中定义一个组件 PostList,用于展示BBS 的帖子列表;定义一个 PostItem,用于接收父组件传来的值,渲染到页面上
PostList 代码如下:
import React, { Component } from 'react' import PostItem from './PostItem' export class PostList extends Component { render() { const data = [ {title: "重磅!党和国家机构改革有新进展",author: "小明",date: "2023-03-01"}, {title: "美环保署前负责人:“毒火车”脱轨地区的环境显然有问题",author: "小虎",date: "2022-01-11"}, {title: "中央网信办所属部分在京事业单位2023年度公开招聘公告",author: "小钰",date: "2021-02-12"}, {title: "北京网络辟谣 互联网联合辟谣平台 网络辟谣标签工作专区",author: "小欧",date: "2011-12-12"} ] return ( <> <h2>贴子列表</h2> {data.map(item=><PostItem title={item.title} author={item.author} date={item.date}></PostItem>)} </> ) } } export default PostListPostItem 代码如下:
import React, { Component } from 'react' export class PostItem extends Component { render() { // 解构 const {title,author,date} = this.props return ( <> <ul> <li> <div>{title}</div> <div> 创建人:<span>{author}</span> </div> <div> 创建时间:<span>{date}</span> </div> </li> </ul> </> ) } } export default PostItem
请注意:使用类样式组件接收父组件传过来的值,用 this.props 就可以直接渲染上去了!!!
3.2、使用函数定义组件,叫函数式组件
import React from "react"; import { Table, Popconfirm, InputNumber } from "antd"; // 函数式组件,在这里接收父组件传过来的值 export default function Tablesss(props) { return <h2>Hello {props.name}!</h2>; }
请注意:使用函数式组件接收父组件传过来的值,需要在函数的参数里面用props来接收 !!!
3.3、组件的规范
-
组件的名称必须首字母大写,react内部会根据这个来判断是组件还是普通的HTML标签
-
函数组件必须有返回值,表示该组件的 UI 结构;如果不需要渲染任何内容,则返回 null
-
组件就像 HTML 标签一样可以被渲染到页面中。组件表示的是一段结构内容,对于函数组件来说,渲染的内容是函数的返回值就是对应的内容
-
使用函数名称作为组件标签名称,可以成对出现也可以自闭合
3.4、有状态组件与无状态组件
3.4.1、有状态组件
-
它属于一个 class 类
-
有继承
-
可以通过this来接收状态和属性
-
如果你想用react的生命周期,想对一些数据进行增删改查的话就要用到有状态组件
3.4.2、无状态组件
-
它属于一个函数
-
没有继承功能
-
没有生命周期
-
他的动态数据都是通过父组件传值子组件通过props接收渲染,针对一些简单的逻辑判断等等,用无状态组件
3.4.3、什么时候用有状态组件
-
在不确定或者确定要用到数据增删改查模块就可以
-
在需要管理状态,或者需要使用生命周期时再用
3.4.4、注意
大部分建议使用无状态组件,因为如果大量用有状态的组件容易触发生命周期和钩子函数,页面会出面加载慢等问题!!!
四、组件三大核心属性
4.1、state
组件的 state 是组件内部的状态,state的变化最终将反映到组件UI的上。我们在组件的构造方法 constructor 中通过 this.state 定义组件的初始状态,并通过调用 this.setState 方法改变组件状态(也是改变组件状态的唯一方式),进而组件UI也会随之重新渲染。
理解:
-
state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
-
组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
-
组件中render方法中的this为组件实例对象
-
组件自定义的方法中this为undefined,如何解决?
注意:
-
组件中render方法中的this为组件实例对象
-
组件自定义的方法中this为undefined,如何解决?
- 强制绑定this: 通过函数对象的 bind()
- 箭头函数
-
状态数据,不能直接修改或更新
4.1.1、this绑定
1、在 constructor 中使用 bind() 进行硬绑定
constructor() { this.handleClick = this.handleClick.bind(this); }
2、直接在元素上使用 bind() 绑定
<label className={className} onClick={this.handleClick.bind(this)}>
3、ES6 有个很有用的语法糖:Arrow Function(箭头函数)它可以很方便的使 this 直接指向 class SwitchButton
<label className={className} onClick={()=>this.handleClick()}>
4.2、props
props就是属性的简写,是单个值,是在父组件中定义或已经在 state 中的值,并将这些值传递给其子组件。props本身不可变,但可以通过触发state的变化,反过来改变props本身的值。
理解:
-
每个组件对象都会有props(properties的简写)属性
-
组件标签的所有属性都保存在props中
作用:
-
用于接收组件外部的数据
-
传递数据: 通过给组件标签添加属性
-
接收数据:函数组件通过 参数 props接收数据,类组件通过 this.props接收数据
特点:
-
可以给组件传递任意类型的数据
-
props是只读属性,不能对值进行修改
-
使用类组件时,如果写了构造函数,应该将props传递给super(),否则无法在构造函数中获取到props,其他的地方是可以拿到的
应用场景:
-
子组件调用父组件的方法
- 子组件要拿到父组件的属性,需要通过
this.props
方法 -
同样地,如果子组件想要调用父组件的方法,只需父组件把要被调用的方法以属性的方式放在子组件上, 子组件内部便可以通过
“this.props.被调用的方法
”这样的方式来获取父组件传过来的方法。
- 子组件要拿到父组件的属性,需要通过
-
父组件调用子组件的方法
- 在 ReactJS 中有个叫 ref 的属性。这个属性就像给组件起个引用名字一样,子组件被设置为 ref 之后(比如 ref=“xxx”)。父组件便可以通过
this.refs.xxx
来获取到子组件了。
- 在 ReactJS 中有个叫 ref 的属性。这个属性就像给组件起个引用名字一样,子组件被设置为 ref 之后(比如 ref=“xxx”)。父组件便可以通过
栗子:React 三大属性之一 props的一些简单理解 - 腾讯云开发者社区-腾讯云 (tencent.com)
编码操作:
- 内部读取某个属性值
- this.props.name
- 扩展属性: 将对象的所有属性通过props传递
-
<Person {...person}/>
-
- 默认属性值:
-
Person.defaultProps = { age: 18, sex:'男' }
-
- 组件类的构造函数
-
constructor(props){ super(props) console.log(props)//打印所有属性 }
-
4.3、refs与事件处理
Refs 是一个 获取 DOM节点或 React元素实例的工具。在 React 中 Refs 提供了一种方式,允许用户访问DOM 节点或者在render方法中创建的React元素
使用情景:
-
对DOM 元素焦点的控制、内容选择或者媒体播放;
-
通过对DOM元素控制,触发动画特效;
-
通第三方DOM库的集成。
编码:
-
字符串形式的ref(不推荐使用,已过时,存在效率问题)
-
<input ref="input1"/>
-
-
回调形式的ref
-
<input ref={(c)=>{this.input1 = c}}
-
<script type="text/babel"> //创建组件 class Demo extends React.Component{ //展示左侧输入框的数据 showData = ()=>{ const {input1} = this alert(input1.value) } //展示右侧输入框的数据 showData2 = ()=>{ const {input2} = this alert(input2.value) } render(){ return( <div> <input ref={c => this.input1 = c } type="text" placeholder="点击按钮提示数据"/> <button onClick={this.showData}>点我提示左侧的数据</button> <input onBlur={this.showData2} ref={c => this.input2 = c } type="text" placeholder="失去焦点提示数据"/> </div> ) } } //渲染组件到页面 ReactDOM.render(<Demo a="1" b="2"/>,document.getElementById('test')) </script>
-
-
createRef创建ref容器
-
myRef = React.createRef()
<input ref={this.myRef}/>
事件处理:
-
通过onXxx属性指定事件处理函数(注意大小写)
-
React使用的是自定义(合成)事件, 而不是使用的原生DOM事件
-
React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)
-
-
通过event.target得到发生事件的DOM元素对象
五、组件的属性校验和默认属性
5.1、特殊属性——propTypes
对 Component 设置 propTypes 属性,可以为 Component 的 props 属性进行类型检查
HiBox 父组件:import React, { Component } from 'react' import Hi,{ Message } from './Hi' import Person from './person'; export default class HiBox extends Component { render() { let age= 19; return ( <div> <Hi age={age} hobby={['阅读','运动','听音乐',1,2,3]} onVote={()=>alert("你好,大美女!")} sex="女" info={new Message()} height={180} mobile={13454367654} name="tao"></Hi> </div> ) } }
Hi 子组件:
import React, { Component } from 'react' import PropTypes from 'prop-types' class Hi extends Component { render() { return ( <div> <h2 onClick={this.props.onVote} style={{cursor: "pointer"}}> Hi,我的姓名为:{this.props.name} <p>我的年龄为:{this.props.age}岁;</p> <p>爱好为:{this.props.hobby.join("、")}</p> <p>性别为:{this.props.sex}</p> <p>身高为:{this.props.height}</p> <p>手机号为:{this.props.mobile}</p> </h2> </div> ) } } // 定义类型 Message export function Message(){ this.show = ()=>{ alert("你好!"); } } // 设置组件Hi的属性 Hi.propTypes = { // 约束age属性为number类型 age: PropTypes.number, // 约束hobby属性为数组类型 hobby: PropTypes.array, // 约束hobby属性必须为number类型的数组 // hobby: PropTypes.arrayOf(PropTypes.number), // 约束onVote属性必须是一个函数 onVote: PropTypes.func, // 限制性别必须为男或女,只能是数组中的某一项 sex: PropTypes.oneOf(["男","女"]), // info属性的值必须是Message类型 // info: PropTypes.instanceOf(Message), // info可以是number类型,string或者Message类型 info: PropTypes.oneOfType([ PropTypes.number, PropTypes.string, PropTypes.instanceOf(Message), ]), // 约束身高必须在179到220之间 height: function(props,propsName,ComponentName){ // 取出属性值 let value = props[propsName]; if (value<170 || value>220) { throw new Error("身高必须在179到220之间") } }, // 约束手机号必须是以1开头的11位数字 mobile: function (props,propsName,ComponentName){ let value = props[propsName]; if (value) { if (!/^1\d{10}$/.test(value)) { throw new Error("手机号必须是以1开头的11位数字") } } }, // name属性必须为string类型而且必须要填写 name:PropTypes.string.isRequired, } export default Hi;
运行结果:
5.2、限制单个子元素
使用 PropTypes.element 你可以指定只有一个子元素可以被传递给组件。
Person 子组件:import React, { Component } from 'react' import PropTypes from 'prop-types' export default class Person extends Component { render() { return ( <div>person</div> ) } } Person.propTypes = { // 限制子元素必须为number类型,而且必填 // children: PropTypes.number.isRequired, // 限制子元素只能为单个元素 children: PropTypes.element.isRequired }HiBox 父组件:
<Person> <span>{19}</span> </Person>
5.3、默认标签属性值
当组件引用的时候,没有传入该sex和age属性时,会使用默认值。
//指定默认标签属性值 Person.defaultProps = { sex:'男',//sex默认值为男 age:18 //age默认值为18 }
六、生命周期
其实React组件并不是真正的DOM, 而是会生成JS对象的虚拟DOM,虚拟DOM会经历创建,更新,删除的过程
这一个完整的过程就构成了组件的生命周期,React 提供了钩子函数让我们可以在组件生命周期的不同阶段添加操作
6.1、理解
-
组件从创建到死亡它会经历一些特定的阶段。
-
React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。
-
我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。
6.2、生命周期流程图
解析:
6.3、react的生命周期大概分为
-
组件装载(Mount)组件第一次渲染到Dom树
-
组件更新(update)组件state,props变化引发的重新渲染
-
组件卸载(Unmount)组件从Dom树删除
6.4、生命周期的三个阶段
1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
- constructor():在此初始化state,绑定成员函数this环境,props本地化,constructor 构造函数只在初始化化的时候执行一次
- getDerivedStateFromProps():在创建时或更新时的render之前执行,让
props
能更新到组件内部state
中,必须是静态的。它应返回一个对象来更新 state,如果返回null
则不更新任何内容。 - render():
渲染函数
,唯一的一定不能省略的函数,必须有返回值,返回null或false表示不渲染任何DOM元素。它是一个仅仅用于渲染的纯函数,返回值完全取决于this.state和this.props,不能在函数中任何修改props、state、拉取数据等具有副作用的操作。render函数返回的是JSX的对象,该函数并不因为这渲染到DOM树,何时进行真正的渲染是有React库决定的。 - componentDidMount():
挂载成功函数
。该函数不会再render函数调用完成之后立即调用,因为render函数仅仅是返回了JSX的对象,并没有立即挂载到DOM树上,而componentDidMount是在组件被渲染到DOM树之后被调用的。另外,componentDidMount函数在进行服务器端渲染时不会被调用。
2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
- getDerivedStateFromProps()
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
- componentWillUnmount()
6.5、重要的勾子函数
-
render:初始化渲染或更新渲染调用
-
componentDidMount:开启监听, 发送ajax请求
-
componentWillUnmount:做一些收尾工作, 如: 清理定时器
6.6、即将废弃的勾子
-
componentWillMount
-
componentWillReceiveProps
-
componentWillUpdate
现在使用会出现警告,下一个大版本需要加上UNSAFE_前缀才能使用,以后可能会被彻底废弃,不建议使用。
6.7、示例说明
6.7.1、组件装载(Mount)
import React, { Component } from "react"; class Hi extends Component { constructor(props) { super(props); console.log("constructor()函数被调用,构造函数"); this.state = { n: 100, }; } render() { console.log("render()函数被调用,返回UI描述"); return <h2>Hello {this.props.name}!</h2>; } static getDerivedStateFromProps() { console.log( "getDerivedStateFromProps()函数被调用,让 props 能更新到组件内部 state中" ); return null; } componentDidMount() { console.log("componentDidMount()函数被调用,组件被挂载到DOM后"); } } export default Hi;
运行结果:
6.7.1.1、构造方法 constructor
说明:
-
如果不需要初始化state,或者不进行方法的绑定,则不需要实现constructor构造函数
-
在组件挂载前调用构造函数,如果继承
React.Component
,则必须调用super(props)
-
constructor通常用于处理了state初始化和为事件处理函数绑定
this
实例 -
尽量避免将props外部数据赋值给组件内部state状态
注意:constructor 构造函数只在初始化化的时候执行一次
栗子:
import React, { Component } from "react"; class Counter extends Component { constructor(props) { super(props); this.state = { count: 0, }; //解决changeWeather中this指向问题 this.handleClick = this.handleClick.bind(this); } handleClick() { console.log(this); this.setState({ count: this.state.count + 1 }); } render() { return ( <div> <h2>计算器</h2> <button onClick={this.handleClick}>点击加1</button> <span> {this.state.count} </span> </div> ); } } export default Counter;
运行结果:
组件 state 也可以不定义在constructor构造函数中,事件函数也可以通过箭头函数处理 this 问题
因此如果不想使用 constructor 也可以将两者移出
import React, { Component } from "react"; class Counter extends Component { //初始化组件状态 state = { count: 0, }; //箭头函数处理this问题,自定义方法——要用赋值语句的形式+箭头函数 handleClick = () => { console.log(this); this.setState(() => ({ count: this.state.count + 1 })); }; render() { return ( <div> <h2>计算器</h2> <button onClick={this.handleClick}>点击加1</button> <span> {this.state.count} </span> </div> ); } } export default Counter;
箭头函数中的this指向了当前组件实例,而普通函数则指向undefined。箭头函数
内this
是词法作用域,由上下文确定。
6.7.1.2、构造方法 constructor
6.7.2、组件更新(update)
6.7.3、组件卸载(Unmount)
标签:render,未完结,DOM,笔记,React,state,props,组件 From: https://www.cnblogs.com/fairya/p/17146642.html