一、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 PostList
PostItem 代码如下:
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、有状态组件

  1. 它属于一个 class 类

  2. 有继承

  3. 可以通过this来接收状态和属性

  4. 如果你想用react的生命周期,想对一些数据进行增删改查的话就要用到有状态组件

3.4.2、无状态组件

  1. 它属于一个函数

  2. 没有继承功能

  3. 没有生命周期

  4. 他的动态数据都是通过父组件传值子组件通过props接收渲染,针对一些简单的逻辑判断等等,用无状态组件

3.4.3、什么时候用有状态组件

  1. 在不确定或者确定要用到数据增删改查模块就可以

  2. 在需要管理状态,或者需要使用生命周期时再用

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 来获取到子组件了。

栗子: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="点击按钮提示数据"/>&nbsp;
      <button onClick={this.showData}>点我提示左侧的数据</button>&nbsp;
      <input onBlur={this.showData2} ref={c => this.input2 = c } type="text" placeholder="失去焦点提示数据"/>&nbsp;
      </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、理解

  1. 组件从创建到死亡它会经历一些特定的阶段。

  2. React组件中包含一系列勾子函数(生命周期回调函数), 会在特定的时刻调用。

  3. 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。

6.2、生命周期流程图

 解析:

6.3、react的生命周期大概分为

  • 组件装载(Mount)组件第一次渲染到Dom树

  • 组件更新(update)组件state,props变化引发的重新渲染

  • 组件卸载(Unmount)组件从Dom树删除

6.4、生命周期的三个阶段

1. 初始化阶段: 由ReactDOM.render()触发---初次渲染

  1. constructor():在此初始化state,绑定成员函数this环境,props本地化,constructor 构造函数只在初始化化的时候执行一次
  2. getDerivedStateFromProps():在创建时或更新时的render之前执行,让 props 能更新到组件内部 state中,必须是静态的。它应返回一个对象来更新 state,如果返回 null 则不更新任何内容。
  3. render():渲染函数,唯一的一定不能省略的函数,必须有返回值,返回null或false表示不渲染任何DOM元素。它是一个仅仅用于渲染的纯函数,返回值完全取决于this.state和this.props,不能在函数中任何修改props、state、拉取数据等具有副作用的操作。render函数返回的是JSX的对象,该函数并不因为这渲染到DOM树,何时进行真正的渲染是有React库决定的。
  4. componentDidMount():挂载成功函数。该函数不会再render函数调用完成之后立即调用,因为render函数仅仅是返回了JSX的对象,并没有立即挂载到DOM树上,而componentDidMount是在组件被渲染到DOM树之后被调用的。另外,componentDidMount函数在进行服务器端渲染时不会被调用。

2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发

  1. getDerivedStateFromProps()
  2. shouldComponentUpdate()
  3. render()
  4. getSnapshotBeforeUpdate()
  5. componentDidUpdate()

3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发

  1. componentWillUnmount()

6.5、重要的勾子函数

  1. render:初始化渲染或更新渲染调用

  2. componentDidMount:开启监听, 发送ajax请求

  3. componentWillUnmount:做一些收尾工作, 如: 清理定时器

6.6、即将废弃的勾子

  1. componentWillMount

  2. componentWillReceiveProps

  3. 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

说明:

  1. 如果不需要初始化state,或者不进行方法的绑定,则不需要实现constructor构造函数

  2. 在组件挂载前调用构造函数,如果继承React.Component,则必须调用super(props)

  3. constructor通常用于处理了state初始化和为事件处理函数绑定this实例

  4. 尽量避免将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)

React 的学习笔记一 (未完结)的更多相关文章

  1. React 入门学习笔记整理目录

    React 入门学习笔记整理(一)--搭建环境 React 入门学习笔记整理(二)-- JSX简介与语法 React 入门学习笔记整理(三)-- 组件 React 入门学习笔记整理(四)-- 事件 R ...

  2. The Road to learn React书籍学习笔记(第二章)

    The Road to learn React书籍学习笔记(第二章) 组件的内部状态 组件的内部状态也称为局部状态,允许保存.修改和删除在组件内部的属性,使用ES6类组件可以在构造函数中初始化组件的状 ...

  3. The Road to learn React书籍学习笔记(第三章)

    The Road to learn React书籍学习笔记(第三章) 代码详情 声明周期方法 通过之前的学习,可以了解到ES6 类组件中的生命周期方法 constructor() 和 render() ...

  4. React Native 学习笔记--进阶(二)--动画

    React Native 进阶(二)–动画 动画 流畅.有意义的动画对于移动应用用户体验来说是非常必要的.我们可以联合使用两个互补的系统:用于全局的布局动画LayoutAnimation,和用于创建更 ...

  5. [Firefly引擎][学习笔记三][已完结]所需模块封装

    原地址:http://www.9miao.com/question-15-54671.html 学习笔记一传送门学习笔记二传送门 学习笔记三导读:        笔记三主要就是各个模块的封装了,这里贴 ...

  6. [Firefly引擎][学习笔记二][已完结]卡牌游戏开发模型的设计

    源地址:http://bbs.9miao.com/thread-44603-1-1.html 在此补充一下Socket的验证机制:socket登陆验证.会采用session会话超时的机制做心跳接口验证 ...

  7. [Firefly引擎][学习笔记四][已完结]服务器端与客户端的通讯

    原地址:http://www.9miao.com/question-15-54981.html 传送门:学习笔记一学习笔记二学习笔记三 前言:学习笔记三是模块封装,这个在持续开发中会不断更新, 因为写 ...

  8. React+Redux学习笔记:React+Redux简易开发步骤

    前言 React+Redux 分为两部分: UI组件:即React组件,也叫用户自定义UI组件,用于渲染DOM 容器组件:即Redux逻辑,处理数据和业务逻辑,支持所有Redux API,参考之前的文 ...

  9. [Firefly引擎][学习笔记一][已完结]带用户验证的聊天室

    原地址:http://bbs.9miao.com/thread-44571-1-1.html 前言:早在群里看到大鸡蛋分享他们团队的Firefly引擎,但一直没有时间去仔细看看,恰好最近需要开发一个棋 ...

  10. React Redux学习笔记

    React Router React Router 使用教程 Redux中间件middleware [译]深入浅出Redux中间件 Redux学习之一:何为middleware? ES6 ES6新特性 ...

随机推荐

  1. 题解 [HDU6746] Civilization(贪心+模拟)

    来源:2020 年百度之星·程序设计大赛 - 初赛一 一道贪心 + 细节模拟题 题意很简单,这里不详细写了 观察题目,\(n\) 只有 500 ,可以 \(n \times n\) 枚举每个位置作为起 ...

  2. 0x62 图论-最小生成树

    A题:走廊泼水节 链接:https://ac.nowcoder.com/acm/contest/1056/A 题目描述 给定一棵N个节点的树,要求增加若干条边,把这棵树扩充为完全图,并满足图的唯一最小 ...

  3. ElementUI - <el-table> 表格 selection 设置的复选框禁止选中某些行

    https://blog.csdn.net/weixin_44198965/article/details/119026054

  4. python · SQL | MySQL 配置与 python 连接数据库

    来存档一下搞 sql 的过程,方便以后查阅. 安装与配置 mysql server:https://blog.csdn.net/zhende_lan/article/details/129318514 ...

  5. React报错之ref返回undefined或null

    正文从这开始~ 总览 当我们试图在其对应的DOM元素被渲染之前访问其current属性时,React的ref通常会返回undefined或者null.为了解决该问题,可以在useEffect钩子中访问 ...

  6. LaTeX 公式识别问题

    问题 想要方便的图片公式识别工具来写Latex(论文)/markdown(笔记)文件 工具推荐 1.mathpix 识别成功率最高(无论是多行,表格表现都非常良好),最好用的工具,但是收费高且付费麻烦 ...

  7. 例2.8 已知带头结点单链表L,设计算法实现:以表中第一元素作为标准,将表中所有值小于第一个元素的结点均放在第一结点之前,所有值大于第一元素的结点均放在第一元素结点之后。

    1.题目 例2.8已知带头结点单链表L,设计算法实现:以表中第一元素作为标准,将表中所有值小于第一个元素的结点均放在第一结点之前,所有值大于第一元素的结点均放在第一元素结点之后. 2.算法分析 3.代 ...

  8. 【KEIL】User's Guide

    µVision User's Guide

  9. [转帖]「开源摘星计划」Prometheus监控Harbor(二进制版)

    推荐 原创 键客李大白2022-08-08 11:35:07博主文章分类:Harbor进阶实战(企业实战)著作权 文章标签云原生运维Harbor文章分类kubernetes云计算私藏项目实操分享阅读数 ...

  10. [转帖]PostgreSQL数据加载工具之pg_bulkload

    https://www.jianshu.com/p/b576207f2f3c 1. pg_bulkload介绍 PostgreSQL提供了一个copy命令的便利数据加载工具,copy命令源于Postg ...