React学习

1、hello React

babel.js 的作用
(1) 浏览器不能直接解析 JSX 代码, 需要 babel 转译为纯 JS 的代码才能运行
(2) 只要用了 JSX,都要加上 type=“text/babel”, 声明需要 babel 来处理

<!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>Document</title>
</head>
<body>
    <!-- 准备好一个容器 -->
    <div id="test"></div>
    <!-- react核心库 -->
    <script src="../../js//react.development.js"></script>
    <!-- 用于支持react支持dom操作 -->
    <script src="../../js//react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转换成js -->
    <script src="../../js/babel.min.js"></script>
    <script type="text/babel">
    // 创建虚拟dom
    const VDOM=<h1>Hello,React</h1>
    // 渲染虚拟dom到页面
    ReactDOM.render(VDOM,document.getElementById('test'));
    
    </script>
</body>
</html>

2、创建虚拟dom的两种方式

  1. 纯 JS 方式(一般不用),如果标签太多,会嵌套太多层
  2. JSX 方式
//纯js方式
<!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>Document</title>
</head>
<body>
    <!-- 准备好一个容器 -->
    <div id="test"></div>
    <!-- react核心库 -->
    <script src="../../js//react.development.js"></script>
    <!-- 用于支持react支持dom操作 -->
    <script src="../../js//react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转换成js -->
    <script src="../../js/babel.min.js"></script>
    <script type="text/javascript">
    // 创建虚拟dom
    // const VDOM=React.createElement(标签名,标签属性,标签内容)
    const VDOM=React.createElement('h1',{id:'title'},React.createElement('span',{},'Hello,React'));
    // 渲染虚拟dom到页面
    ReactDOM.render(VDOM,document.getElementById('test'));
    
    </script>
</body>
</html>
//JSX方式
<!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>Document</title>
</head>
<body>
    <!-- 准备好一个容器 -->
    <div id="test"></div>
    <!-- react核心库 -->
    <script src="../../js//react.development.js"></script>
    <!-- 用于支持react支持dom操作 -->
    <script src="../../js//react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转换成js -->
    <script src="../../js/babel.min.js"></script>
    <script type="text/babel">
    // 创建虚拟dom
    const VDOM=(
        <h1 id="title">
        <span>Hello,React</span>    
        </h1>
    )
    // 渲染虚拟dom到页面
    ReactDOM.render(VDOM,document.getElementById('test'));
    
    </script>
</body>
</html>

React 提供了一些 API 来创建一种 “特别” 的一般 js 对象

const VDOM = React.createElement('xx',{id:'xx'},'xx')

上面创建的就是一个简单的虚拟 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>Document</title>
</head>
<body>
    <!-- 准备好一个容器 -->
    <div id="test"></div>
    <div id="demo"></div>
    <!-- react核心库 -->
    <script src="../../js//react.development.js"></script>
    <!-- 用于支持react支持dom操作 -->
    <script src="../../js//react-dom.development.js"></script>
    <!-- 引入babel,用于将jsx转换成js -->
    <script src="../../js/babel.min.js"></script>
    <script type="text/babel">
    // 创建虚拟dom
    const VDOM=(
        <h1 id="title">
        <span>Hello,React</span>    
        </h1>
    )
    // 渲染虚拟dom到页面
    ReactDOM.render(VDOM,document.getElementById('test'));
    console.log(VDOM);
    console.log(typeof VDOM);
    console.log(document.getElementById('demo'));
    </script>
</body>
</html>

在这里插入图片描述

  • 虚拟 DOM 对象最终都会被 React 转换为真实的 DOM
  • 我们编码时基本只需要操作 react 的虚拟 DOM 相关数据, react 会转换为真实
    DOM 变化而更新界。

3、jsx语法规则:

全称: JavaScript XML

  • react 定义的一种类似于 XML 的 JS 扩展语法: JS + XML 本质是
    React.createElement(component, props, …children)方法的语法糖
  • 作用: 用来简化创建虚拟 DOM
  • 写法:var ele = <h1>Hello JSX!</h1>
  • 它不是字符串, 也不是 HTML/XML 标签
  • 它最终产生的就是一个 JS 对象

1.定义虚拟DOM时,不要写引号。
2.标签中混入JS表达式时要用{}。
3.样式的类名指定不要用class,要用className。
4.内联样式,要用style={{key:value}}的形式去写。
5.只有一个根标签
6.标签必须闭合
7.标签首字母
(1).若小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错。
(2).若大写字母开头,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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
    <style>
        .title{
            background-color: orange;
            width: 200px;
        }
    </style>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    const myId="demo";
    const myData="Hello,React";
    const VDOM=(
        <div>
            <h2 className="title" id={myId.toLowerCase()}>
                {myData}
            </h2>
            <span className="title" id={myId.toUpperCase()} style={{backgroundColor:"blue",fontSize:"26px"}}>{myData}</span>
            <input type="text"/>
        </div>
    )
    ReactDOM.render(VDOM,document.getElementById('test'));
    </script>
</body>
</html>

在这里插入图片描述
练习

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>jsx小练习</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入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']
		//1.创建虚拟DOM
		const VDOM = (
			<div>
				<h1>前端js框架列表</h1>
				<ul>
					{
						data.map((item,index)=>{
							return <li key={index}>{item}</li>
						})
					}
				</ul>
			</div>
		)
		//2.渲染虚拟DOM到页面
		ReactDOM.render(VDOM,document.getElementById('test'))
	</script>
</body>
</html>

在这里插入图片描述

一定注意区分:【js语句(代码)】与【js表达式】
1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
下面这些都是表达式:(可以用const a=…表达)
(1). a
(2). a+b
(3). demo(1)
(4). arr.map()
(5). function test () {}
2.语句(代码):
下面这些都是语句(代码):
(1).if(){}
(2).for(){}
(3).switch(){case:xxxx}

4、模块与组件、模块化与组件化

4.1、模块

  1. 理解:向外提供特定功能的 js 程序, 一般就是一个 js 文件
  2. 为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂。
  3. 作用:复用 js, 简化 js 的编写, 提高 js 运行效率

4.2、组件

  1. 理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image 等等)
  2. 为什么要用组件: 一个界面的功能更复杂
  3. 作用:复用编码, 简化项目编码, 提高运行效率

4.3、模块化

当应用的 js 都以模块来编写的, 这个应用就是一个模块化的应用

4.4、组件化

当应用是以多组件的方式实现, 这个应用就是一个组件化的应用

5、组件

5.1、函数式组件

1.React解析组件标签,找到了函数式组件。
2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
3.组件名和标签必须大写,函数必须要有返回值

<!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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    // 创建函数式组件
    function Demo(){
        console.log(this);
        return <h2> 我是用函数定义的组件(适用于简单组件的定义)</h2>
    }
    ReactDOM.render(<Demo/>,(document.getElementById('test')));
    </script>
</body>
</html>

在这里插入图片描述
在这里插入图片描述

5.2、类式组件

执行了ReactDOM.render(<MyComponent/>,.......)之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
3.将render返回的虚拟DOM转为真实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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    // 创建类式定义组件
    class Demo extends React.Component{
        render(){
            return <h2>我是用类定义的组件(适用于复杂组件的定义) </h2>
        }
    }
    ReactDOM.render(<Demo/>,(document.getElementById('test')));
    </script>
</body>
</html>

6、组件实例的三大属性state

6.1、state中this指向

<!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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    // 创建类式定义组件
    class Demo extends React.Component{
        constructor(props){
            super(props)
            //初始化状态
            this.state={
                isHot:true
            }
        }
        render(){
            const {isHot}=this.state;
            return <h2>今天天气很{isHot?'炎热':'凉爽'}</h2>
        }
    }
    ReactDOM.render(<Demo/>,(document.getElementById('test')));
    </script>
</body>
</html>

在这里插入图片描述

<!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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    // 创建类式定义组件
    class Demo extends React.Component{
        constructor(props){
            super(props)
            this.state={
                isHot:true
            }
        }
        render(){
            const {isHot}=this.state;
            return <h2 onClick={changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2>
        }
    }
    ReactDOM.render(<Demo/>,(document.getElementById('test')));
    function changeWeather(){
        console.log("标题被点击了");
    }
    </script>
</body>
</html>

在这里插入图片描述
如果是

 render(){
            const {isHot}=this.state;
            return <h2 onClick={demo()}>今天天气很{isHot?'炎热':'凉爽'}</h2>
        }

将会调用demo函数,没有点击控制台也会输出,undifined作为onClick的回调了

<!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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    // 创建类式定义组件
    class Demo extends React.Component{
        constructor(props){
            super(props)
            this.state={
                isHot:true
            }
        }
//render是放在哪里的?—— Demo的原型对象上,供实例使用。
//render中的this是谁?—— Demo的实例对象 <=> Demo组件实例对象。
        render(){
            const {isHot}=this.state;
            return <h2 onClick={changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2>
        }
    }
    ReactDOM.render(<Demo/>,(document.getElementById('test')));
    function changeWeather(){
        console.log(this);
        console.log("标题被点击了");
    }
    </script>
</body>
</html>

在这里插入图片描述
babel在翻译的时候,禁止自定义函数指向window,所以changeWeather方法里触碰不到组件实例对象,不能读取

<!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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    // 创建类式定义组件
    class Demo extends React.Component{
        constructor(props){
            super(props)
            this.state={
                isHot:true
            }
        }
        render(){
            const {isHot}=this.state;
            return <h2 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2>
        }
        changeWeather()
        {
        console.log(this);
        }
    }
    ReactDOM.render(<Demo/>,(document.getElementById('test')));
    </script>
</body>
</html>

在这里插入图片描述
changWeather已经放在类中了,是类中的方法了,render也是类中的方法,但是render中的this指向没有问题,因为执行了ReactDOM.render(<组件名/>…)之后,React解析组件标签,找到了组件。发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
所以render方法有被组件实例调用。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Document</title>
	</head>
	<body>
		<script type="text/javascript" >
			class Person {
				constructor(name,age){
					this.name = name
					this.age = age
				}
				study(){
					//study方法放在了哪里?——类的原型对象上,供实例使用
					//通过Person实例调用study时,study中的this就是Person实例
					console.log(this);
				}
			}

			const p1 = new Person('tom',18)
			p1.study() //通过实例调用study方法
			const x = p1.study
			x()
		</script>
	</body>
</html>

在这里插入图片描述
相当于x是study方法的另一个引用,x()相当于直接调用,如果是直接调用,this会指向window,但是类中自定义方法都局部开启了严格模式,所以调用后this指向是undifine

<!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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    // 创建类式定义组件
    class Demo extends React.Component{
        constructor(props){
            super(props)
            this.state={
                isHot:true
            }
        }
        render(){
            const {isHot}=this.state;
            return <h2 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2>
        }
        changeWeather()
        {
        console.log(this);
        }
    }
    ReactDOM.render(<Demo/>,(document.getElementById('test')));
    </script>
</body>
</html>

所以这里面<h2 onClick={this.changeWeather}>相当于直接找到了changeWeather方法把它交给了onClick,一点击就直接调用这个方法了,不是实例对象调用的

<!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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    // 创建类式定义组件
    class Demo extends React.Component{
        constructor(props){
            super(props)
            this.state={
                isHot:true
            }
        }
        render(){
            const {isHot}=this.state;
            return <h2 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2>
        }
        changeWeather()
        {
        console.log(this);
        }
    }
    ReactDOM.render(<Demo/>,(document.getElementById('test')));
    const d=new Demo();
    d.changeWeather();
    </script>
</body>
</html>

模拟实例对象调用,谁调用指向谁,所以this指向实例对象
在这里插入图片描述
总的来说,就是

  • changeWeather放在哪里? ———— Weather的原型对象上,供实例使用
  • 由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
  • 类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined

6.2、this指向解决

<!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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    // 创建类式定义组件
    class Demo extends React.Component{
        constructor(props){
            super(props)
            this.state={
                isHot:true
            }
            this.changeWeather=this.changeWeather.bind(this);
        }
        render(){
            const {isHot}=this.state;
            return <h2 onClick={this.changeWeather}>今天天气很{isHot?'炎热':'凉爽'}</h2>
        }
        changeWeather()
        {
        console.log(this);
        }
    }
    ReactDOM.render(<Demo/>,(document.getElementById('test')));
    </script>
</body>
</html>

构造器中的this就是指向实例对象。

  this.changeWeather=this.changeWeather.bind(this);
  • 第一个this指向实例对象,第二个this也指向实例对象。
  • 看右边式子,虽然实例对象中没有changeWeather这个方法,但是会顺着原型链去找,然后就找到了方法,bind()会生产一个函数,同时根据传递的第一个参数改变this指向,第三个当前也是指向实例对象的,所以生产一个新的函数的this指向改成指向构造器。
  • 然后你有了一个指向实例对象的函数了。把这个函数放在了这个实例对象自身,并且把它命名为changeWeather
    在这里插入图片描述

bind 没有规定,传递值和数组都可以。call 和 apply 函数的执行是直接执行的,而 bind 函数会返回一个函数,然后我们想要调用的时候才会执行。
然后点击后,触发的是实例对象上的changeWeather了,而不是顺着原型链找到的changeWeather了
在这里插入图片描述
改下名字,测试一下

<!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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    // 创建类式定义组件
    class Demo extends React.Component{
        constructor(props){
            super(props)
            this.state={
                isHot:true
            }
            this.tool=this.changeWeather.bind(this);
        }
        render(){
            const {isHot}=this.state;
            return <h2 onClick={this.tool}>今天天气很{isHot?'炎热':'凉爽'}</h2>
        }
        changeWeather()
        {
        console.log(this);
        }
    }
    ReactDOM.render(<Demo/>,(document.getElementById('test')));
    </script>
</body>
</html>

6.3、setState的使用

<!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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    // 创建类式定义组件
    class Demo extends React.Component{
        constructor(props){
            super(props)
            this.state={
                isHot:true
            }
            this.tool=this.changeWeather.bind(this);
        }
        render(){
            const {isHot}=this.state;
            return <h2 onClick={this.tool}>今天天气很{isHot?'炎热':'凉爽'}</h2>
        }
        changeWeather()
        {
        this.state.isHot=!this.state.isHot
        console.log(this.state.isHot)
        }
    }
    ReactDOM.render(<Demo/>,(document.getElementById('test')));
    </script>
</body>
</html>

多次点击,页面没有变化,但是控制台会有输出
在这里插入图片描述
改了但是没完全改,react不认可

状态不可直接更改,要借助一个内置的api
这是直接更改,是错误的

 this.state.isHot=!this.state.isHot

调用setState

<!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>Document</title>
    <script src="../../js//react.development.js"></script>
    <script src="../../js//react-dom.development.js"></script>
    <script src="../../js/babel.min.js"></script>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
    // 创建类式定义组件
    class Demo extends React.Component{
        constructor(props){
            super(props)
            this.state={
                isHot:true
            }
            this.tool=this.changeWeather.bind(this);
        }
        render(){
            const {isHot}=this.state;
            return <h2 onClick={this.tool}>今天天气很{isHot?'炎热':'凉爽'}</h2>
        }
        changeWeather()
        {
        const isHot=this.state.isHot;
       console.log(this);
       this.setState({isHot:!isHot})
       console.log(this.state.isHot);
       
        }
    }
    ReactDOM.render(<Demo/>,(document.getElementById('test')));
    </script>
</body>
</html>

在这里插入图片描述
状态必须通过setState进行更新,且更新是一种合并,不是替换。其他状态值不会受到影响

6.4、简写state

类中可以直接写赋值语句,含义是给类的实例对象添加一个属性

class Car {
			constructor(name,price){
				this.name = name
				this.price = price
				// this.wheel = 4
			}
			//类中可以直接写赋值语句,如下代码的含义是:给Car的实例对象添加一个属性,名为a,值为1
			a = 1
			wheel = 4
			static demo = 100
		}
		const c1 = new Car('奔驰c63',199)
		console.log(c1);
		console.log(Car.demo);

在这里插入图片描述
组件的实例对象添加一个箭头函数,由于箭头函数中没有this,将从上下文寻找this,此时箭头函数中this指向实例对象

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>state简写方式</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入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">
		//1.创建组件
		class Weather extends React.Component{
			//初始化状态
			state = {isHot:false,wind:'微风'}

			render(){
				const {isHot,wind} = this.state
				return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'}{wind}</h1>
			}

			//自定义方法————要用赋值语句的形式+箭头函数
			changeWeather = ()=>{
				const isHot = this.state.isHot
				this.setState({isHot:!isHot})
			}
		}
		//2.渲染组件到页面
		ReactDOM.render(<Weather/>,document.getElementById('test'))
				
	</script>
</body>
</html>

在这里插入图片描述

6.5、总结

  1. 组件中 render 方法中的 this 为组件实例对象
  2. 组件自定义的方法中 this 为 undefined,如何解决?
    a) 强制绑定 this: 通过函数对象的 bind()
    b) 箭头函数
  3. 状态数据,不能直接修改或更新

7、组件实例的三大属性props

7.1、基本使用

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>state简写方式</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test1"></div>
    <div id="test2"></div>
    <div id="test3"></div>
	
	<!-- 引入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">
		//1.创建组件
		class Weather extends React.Component{
			render(){
                console.log(this);
				return( 
                    <ul>
                    <li>{this.props.name}</li>
                    <li>{this.props.age}</li>
                    </ul>
                    )
			}

		}
		ReactDOM.render(<Weather name="tom" age="19"/>,document.getElementById('test1'))
        ReactDOM.render(<Weather name="jack"age="18"/>,document.getElementById('test2'))
        ReactDOM.render(<Weather name="mike"age="17"/>,document.getElementById('test3'))
				
	</script>
</body>
</html>

在这里插入图片描述
在这里插入图片描述

7.2、批量传递props

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>state简写方式</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test1"></div>
    <div id="test2"></div>
    <div id="test3"></div>
	
	<!-- 引入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">
		//1.创建组件
		class Weather extends React.Component{
			render(){
                const {name,age}=this.props;
                console.log(this);
				return( 
                    <ul>
                    <li>{name}</li>
                    <li>{age}</li>
                    </ul>
                    )
			}

		}
        const p={
            name:'jack',
            age:19
        }
        // ReactDOM.render(<Weather name={p.name}age={p.age}/>,document.getElementById('test1'))			
		ReactDOM.render(<Weather {...p}/>,document.getElementById('test1'))			
	</script>
</body>
</html>

7.3、对props进行限制

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>state简写方式</title>
</head>
<body>
	<div id="test1"></div>
	<script type="text/javascript" src="../../js/react.development.js"></script>
	<script type="text/javascript" src="../../js/react-dom.development.js"></script>
	<script type="text/javascript" src="../../js/babel.min.js"></script>
   <!-- 引入prop-types,用于对组件标签属性进行限制 -->
    <script type="text/javascript" src="../../js/prop-types.js"></script>
	<script type="text/babel">
		//1.创建组件
		class Person extends React.Component{
			render(){
                const {name,age,sex,speak}=this.props;
                console.log(this);
				return( 
                    <ul>
                    <li>{name}</li>
                    <li>{age}</li>
                    <li>{sex}</li>
                    </ul>
                    )
			}

		}
        Person.propTypes={
            name:PropTypes.string.isRequired,//限制name为字符串且必传
            age:PropTypes.number,//限制age为number类型
            speak:PropTypes.func//限制speak为函数类型,为了避免和原生js中的关键字function冲突,所以是func

        }
        Person.defaultProps={
            sex:'男',//sex默认值为男
            age:18//age默认值为18
        }
		ReactDOM.render(<Person name="jack" age={19} speak='1'/>,document.getElementById('test1'))	
        function speak()
        {
            console.log("你好哇");
        }
	</script>
</body>
</html>

在这里插入图片描述
在这里插入图片描述

7.4、props简写

props只能读不能改
类中可以直接写赋值语句,含义是给类的实例对象添加一个属性

class Car {
			constructor(name,price){
				this.name = name
				this.price = price
				// this.wheel = 4
			}
			//类中可以直接写赋值语句,如下代码的含义是:给Car的实例对象添加一个属性,名为a,值为1
			a = 1
			wheel = 4
			static demo = 100//相当于在类的外面写Car.demo=100
		}
		const c1 = new Car('奔驰c63',199)
		console.log(c1);
		console.log(Car.demo);

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>state简写方式</title>
</head>
<body>
	<div id="test1"></div>
	<script type="text/javascript" src="../../js/react.development.js"></script>
	<script type="text/javascript" src="../../js/react-dom.development.js"></script>
	<script type="text/javascript" src="../../js/babel.min.js"></script>
   <!-- 引入prop-types,用于对组件标签属性进行限制 -->
    <script type="text/javascript" src="../../js/prop-types.js"></script>
	<script type="text/babel">
		//1.创建组件
		class Person extends React.Component{
        static propTypes={
            name:PropTypes.string.isRequired,//限制name为字符串且必传
            age:PropTypes.number,//限制age为number类型
            speak:PropTypes.func//限制speak为函数类型,为了避免和原生js中的关键字function冲突,所以是func

        }
        static defaultProps={
            sex:'男',//sex默认值为男
            age:18//age默认值为18
        }
			render(){
                const {name,age,sex,speak}=this.props;
                console.log(this);
				return( 
                    <ul>
                    <li>{name}</li>
                    <li>{age}</li>
                    <li>{sex}</li>
                    </ul>
                    )
			}

		}
		ReactDOM.render(<Person name="jack" age={19} speak='1'/>,document.getElementById('test1'))	
        function speak()
        {
            console.log("你好哇");
        }
	</script>
</body>
</html>

7.5、props与构造器

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>对props进行限制</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test1"></div>
	<div id="test2"></div>
	<div id="test3"></div>
	
	<!-- 引入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>
	<!-- 引入prop-types,用于对组件标签属性进行限制 -->
	<script type="text/javascript" src="../js/prop-types.js"></script>

	<script type="text/babel">
		//创建组件
		class Person extends React.Component{

			constructor(props){
				//构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props
				// console.log(props);
				super(props)
				console.log('constructor',this.props);
			}

			//对标签属性进行类型、必要性的限制
			static propTypes = {
				name:PropTypes.string.isRequired, //限制name必传,且为字符串
				sex:PropTypes.string,//限制sex为字符串
				age:PropTypes.number,//限制age为数值
			}

			//指定默认标签属性值
			static defaultProps = {
				sex:'男',//sex默认值为男
				age:18 //age默认值为18
			}
			
			render(){
				// console.log(this);
				const {name,age,sex} = this.props
				//props是只读的
				//this.props.name = 'jack' //此行代码会报错,因为props是只读的
				return (
					<ul>
						<li>姓名:{name}</li>
						<li>性别:{sex}</li>
						<li>年龄:{age+1}</li>
					</ul>
				)
			}
		}

		//渲染组件到页面
		ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
	</script>
</body>
</html>

7.6、函数式组件使用props

函数式组件里面没有实例对象,三大属性按道理都不能使用,但是可以使用props,但是函数可以接受参数

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>对props进行限制</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test1"></div>
	<div id="test2"></div>
	<div id="test3"></div>
	
	<script type="text/javascript" src="../js/react.development.js"></script>
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<script type="text/javascript" src="../js/babel.min.js"></script>
	<script type="text/javascript" src="../js/prop-types.js"></script>

	<script type="text/babel">
		//创建组件
		function Person (props){
			const {name,age,sex} = props
			return (
					<ul>
						<li>姓名:{name}</li>
						<li>性别:{sex}</li>
						<li>年龄:{age}</li>
					</ul>
				)
		}
		Person.propTypes = {
			name:PropTypes.string.isRequired, //限制name必传,且为字符串
			sex:PropTypes.string,//限制sex为字符串
			age:PropTypes.number,//限制age为数值
		}

		//指定默认标签属性值
		Person.defaultProps = {
			sex:'男',//sex默认值为男
			age:18 //age默认值为18
		}
		//渲染组件到页面
		ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
	</script>
</body>
</html>

8、refs属性

组件内的标签可以定义 ref 属性来标识自己

8.1、字符串形式ref

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>state简写方式</title>
</head>
<body>
	<div id="test1"></div>
	<script type="text/javascript" src="../../js/react.development.js"></script>
	<script type="text/javascript" src="../../js/react-dom.development.js"></script>
	<script type="text/javascript" src="../../js/babel.min.js"></script>
    <script type="text/javascript" src="../../js/prop-types.js"></script>
	<script type="text/babel">
	class Demo extends React.Component
    {
        showData=()=>{
            console.log(this);
            console.log(this.refs.input1);
            console.log(this.refs.input1.value);
        }
        showData2=()=>{
            console.log(this.refs.input2.value);
        }
        render()
        {
            return(
                <div>
                <input ref="input1" type="text"/>
                <button onClick={this.showData}>点击显示内容</button>    
                <input ref='input2' onBlur={this.showData2} type="text"/>
                </div>
            )
        }        

    }
    ReactDOM.render(<Demo/>,document.getElementById('test1'));
	</script>
</body>
</html>

在这里插入图片描述

8.2、回调形式的ref

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>state简写方式</title>
</head>
<body>
	<div id="test1"></div>
	<script type="text/javascript" src="../../js/react.development.js"></script>
	<script type="text/javascript" src="../../js/react-dom.development.js"></script>
	<script type="text/javascript" src="../../js/babel.min.js"></script>
    <script type="text/javascript" src="../../js/prop-types.js"></script>
	<script type="text/babel">
	class Demo extends React.Component
    {
        showData=()=>{
            console.log(this.input1.value);
           
        }
        showData2=()=>{
            console.log(this.input2.value);
           
        }
        render()
        {
            return(
                <div>
                <input ref={(node)=>{console.log(node);this.input1=node;console.log(this)}} type="text"/>
                <button onClick={this.showData}>点击显示内容</button>    
                <input ref={(node)=>{console.log(node);this.input2=node,console.log(this)}} onBlur={this.showData2} type="text"/>
                </div>
            )
        }        

    }
    ReactDOM.render(<Demo/>,document.getElementById('test1'));
	</script>
</body>
</html>

实例对象调用render方法,由于箭头函数没有指定的this,向外面找,于是指向实例对象this.input1=node,给实例对象添加了一个属性
在这里插入图片描述

8.3、refs调用次数

如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>state简写方式</title>
</head>
<body>
	<div id="test1"></div>
	<script type="text/javascript" src="../../js/react.development.js"></script>
	<script type="text/javascript" src="../../js/react-dom.development.js"></script>
	<script type="text/javascript" src="../../js/babel.min.js"></script>
    <script type="text/javascript" src="../../js/prop-types.js"></script>
	<script type="text/babel">
	class Demo extends React.Component
    {
        state={isHot:true}
        showData=()=>{
            console.log(this.input1.value);
           
        }
        showData2=()=>{
            console.log(this.input2.value);
           
        }
        change=()=>{
            let {isHot}=this.state;
            this.setState({isHot:!isHot})
        }
        render()
        {
            return(
                <div>
                    <h1>今天天气很{this.state.isHot?'炎热':'凉爽'}</h1>
                    <button onClick={this.change}>点击切换</button>
                <input ref={(node)=>{console.log(node);}} type="text"/>
                <button onClick={this.showData}>点击显示内容</button>    
                </div>
            )
        }        

    }
    ReactDOM.render(<Demo/>,document.getElementById('test1'));
	</script>
</body>
</html>

在这里插入图片描述
ref 的回调函数定义成 class 的绑定函数的方式

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>state简写方式</title>
</head>
<body>
	<div id="test1"></div>
	<script type="text/javascript" src="../../js/react.development.js"></script>
	<script type="text/javascript" src="../../js/react-dom.development.js"></script>
	<script type="text/javascript" src="../../js/babel.min.js"></script>
    <script type="text/javascript" src="../../js/prop-types.js"></script>
	<script type="text/babel">
	class Demo extends React.Component
    {
        state={isHot:true}
        showData=()=>{
            console.log(this.input1.value);
           
        }
        showData2=()=>{
            console.log(this.input2.value);
           
        }
        change=()=>{
            let {isHot}=this.state;
            this.setState({isHot:!isHot})
        }
        showNode=(node)=>{
            console.log(node);
            this.input1=node;
        }
        render()
        {
            return(
                <div>
                    <h1>今天天气很{this.state.isHot?'炎热':'凉爽'}</h1>
                    <button onClick={this.change}>点击切换</button>
                <input ref={this.showNode} type="text"/>
                <button onClick={this.showData}>点击显示内容</button>    
                </div>
            )
        }        

    }
    ReactDOM.render(<Demo/>,document.getElementById('test1'));
	</script>
</body>
</html>

8.4、createRef

React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>state简写方式</title>
</head>
<body>
	<div id="test1"></div>
	<script type="text/javascript" src="../../js/react.development.js"></script>
	<script type="text/javascript" src="../../js/react-dom.development.js"></script>
	<script type="text/javascript" src="../../js/babel.min.js"></script>
    <script type="text/javascript" src="../../js/prop-types.js"></script>
	<script type="text/babel">
	class Demo extends React.Component
    {
        myref=React.createRef();
        myref2=React.createRef();
        showData=()=>{
            console.log(this.myref.current.value);
           
        }
        showData2=()=>{
            console.log(this.myref2.current.value);
           
        }
        render()
        {
            return(
                <div>
                <input ref={this.myref} type="text"/>
                <button onClick={this.showData}>点击显示内容</button>    
                <input ref={this.myref2} onBlur={this.showData2} type="text"/>
                </div>
            )
        }        

    }
    ReactDOM.render(<Demo/>,document.getElementById('test1'));
	</script>
</body>
</html>

9、事件处理

  1. 通过 onXxx 属性指定事件处理函数(注意大小写)
    React 使用的是自定义(合成)事件, 而不是使用的原生 DOM 事件,为了更好的兼容性
    React 中的事件是通过事件委托方式处理的(委托给组件最外层的元素),为了的高效
  2. 通过 event.target 得到发生事件的 DOM 元素对象,不要过度使用ref
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
</head>
<body>
	<div id="test1"></div>
	<script type="text/javascript" src="../../js/react.development.js"></script>
	<script type="text/javascript" src="../../js/react-dom.development.js"></script>
	<script type="text/javascript" src="../../js/babel.min.js"></script>
    <script type="text/javascript" src="../../js/prop-types.js"></script>
	<script type="text/babel">
	class Demo extends React.Component
    {
        myref=React.createRef();
        myref2=React.createRef();
        showData=()=>{
            console.log(this.myref.current.value);
           
        }
        showData2=(event)=>{
            console.log(event.target);
           
        }
        render()
        {
            return(
                <div>
                <input ref={this.myref} type="text"/>
                <button onClick={this.showData}>点击显示内容</button>    
                <input ref={this.myref2} onBlur={this.showData2} type="text"/>
                </div>
            )
        }        

    }
    ReactDOM.render(<Demo/>,document.getElementById('test1'));
	</script>
</body>
</html>

点击第二个输入框输入,然后失去焦点
在这里插入图片描述

10、收集表单数据

10.1、非受控组件

表单数据由DOM本身处理。即不受setState()的控制,与传统的HTML表单输入相似,input输入值即显示最新值(使用 ref从DOM获取表单值)

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
</head>
<body>
	<div id="test1"></div>
	<script type="text/javascript" src="../../js/react.development.js"></script>
	<script type="text/javascript" src="../../js/react-dom.development.js"></script>
	<script type="text/javascript" src="../../js/babel.min.js"></script>
    <script type="text/javascript" src="../../js/prop-types.js"></script>
	<script type="text/babel">
	class Login extends React.Component
    {
        handleSubmit=(event)=>{
            event.preventDefault() //阻止表单提交
				const {username,password} = this
				console.log(`你输入的用户名是:${username.value},你输入的密码是:${password.value}`)
        }
        render(){
            return(
            <form onSubmit={this.handleSubmit}>
            用户名:<input type="text" name="userName"ref={(node)=>{this.username=node}}/>    
            密码:<input type="password" name="password" ref={(node)=>{this.password=node}}/>
            <button>提交</button>    
            </form>
            )
        }
    }
    ReactDOM.render(<Login/>,document.getElementById('test1'));
	</script>
</body>
</html>

10.2、受控组件

在React中,可变状态通常保存在组件的状态属性中,并且只能使用 setState() 更新,而呈现表单的React组件也控制着在后续用户输入时该表单中发生的情况,以这种由React控制的输入表单元素而改变其值的方式,称为:“受控组件”。

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>2_受控组件</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入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">
		//创建组件
		class Login extends React.Component{

			//初始化状态
			state = {
				username:'', //用户名
				password:'' //密码
			}

			//保存用户名到状态中
			saveUsername = (event)=>{
				this.setState({username:event.target.value})
			}

			//保存密码到状态中
			savePassword = (event)=>{
				this.setState({password:event.target.value})
			}

			//表单提交的回调
			handleSubmit = (event)=>{
				event.preventDefault() //阻止表单提交
				const {username,password} = this.state
				alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
			}

			render(){
				return(
					<form onSubmit={this.handleSubmit}>
						用户名:<input onChange={this.saveUsername} type="text" name="username"/>
						密码:<input onChange={this.savePassword} type="password" name="password"/>
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login/>,document.getElementById('test'))
	</script>
</body>
</html>

11、函数柯里化

高阶函数:
如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数。
1.若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数。
2.若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数。
常见的高阶函数有:Promise、setTimeout、arr.map()等等
函数的柯里化:
通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Document</title>
	</head>
	<body>
		<script type="text/javascript" >
			/* function sum(a,b,c){
				return a+b+c
			} */
			
			function sum(a){
				return(b)=>{
					return (c)=>{
						return a+b+c
					}
				}
			}
			const result = sum(1)(2)(3)
			console.log(result);
		</script>
	</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>2_受控组件</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入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">
		//创建组件
		class Login extends React.Component{

			//初始化状态
			state = {
				username:'', //用户名
				password:'' //密码
			}
            saveFormData=(typeData)=>{
                console.log(typeData);
                return (event)=>{
                    this.setState({[typeData]:event.target.value});
                }
            }
		
			//表单提交的回调
			handleSubmit = (event)=>{
				event.preventDefault() //阻止表单提交
				const {username,password} = this.state
				alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
			}
			render(){
				return(
					<form onSubmit={this.handleSubmit}>
						用户名:<input onChange={this.saveFormData('username')} type="text" name="username"/>
						密码:<input onChange={this.saveFormData('password')} type="password" name="password"/>
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login/>,document.getElementById('test'))
	</script>
</body>
</html>

onChange实际上调用的是saveFormData返回的函数

不用柯里化

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>2_受控组件</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入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">
		//创建组件
		class Login extends React.Component{

			//初始化状态
			state = {
				username:'', //用户名
				password:'' //密码
			}
            saveFormData=(typeData,value)=>{
                    this.setState({[typeData]:value});
            }
		
			//表单提交的回调
			handleSubmit = (event)=>{
				event.preventDefault() //阻止表单提交
				const {username,password} = this.state
				alert(`你输入的用户名是:${username},你输入的密码是:${password}`)
			}
			render(){
				return(
					<form onSubmit={this.handleSubmit}>
						用户名:<input onChange={(event)=>{this.saveFormData('username',event.target.value)}} type="text" name="username"/>
						密码:<input onChange={(event)=>{this.saveFormData('password',event.target.value)}} type="password" name="password"/>
						<button>登录</button>
					</form>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Login/>,document.getElementById('test'))
	</script>
</body>
</html>

12、生命周期函数(旧)

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>1_引出生命周期</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入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">
		//创建组件
		//生命周期回调函数 <=> 生命周期钩子函数 <=> 生命周期函数 <=> 生命周期钩子
		class Life extends React.Component{

			state = {opacity:1}

			death = ()=>{
				//卸载组件
				ReactDOM.unmountComponentAtNode(document.getElementById('test'))
			}

			//组件挂完毕
			componentDidMount(){
				console.log('componentDidMount');
				this.timer = setInterval(() => {
					//获取原状态
					let {opacity} = this.state
					//减小0.1
					opacity -= 0.1
					if(opacity <= 0) opacity = 1
					//设置新的透明度
					this.setState({opacity})
				}, 200);
			}

			//组件将要卸载
			componentWillUnmount(){
				//清除定时器
				clearInterval(this.timer)
			}

			//初始化渲染、状态更新之后
			render(){
				console.log('render');
				return(
					<div>
						<h2 style={{opacity:this.state.opacity}}>React学不会怎么办?</h2>
						<button onClick={this.death}>不活了</button>
					</div>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Life/>,document.getElementById('test'))
	</script>
</body>
</html>

12.1、初始化阶段

由ReactDOM.render()触发—初次渲染

  • constructor()
  • componentWillMount()
  • render()
  • componentDidMount()=====> 常用一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>2_react生命周期()</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入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">
		//创建组件
		class Count extends React.Component{

			//构造器
			constructor(props){
				console.log('Count---constructor');
				super(props)
				//初始化状态
				this.state = {count:0}
			}

			//加1按钮的回调
			add = ()=>{
				//获取原状态
				const {count} = this.state
				//更新状态
				this.setState({count:count+1})
			}

			//组件将要挂载的钩子
			componentWillMount(){
				console.log('Count---componentWillMount');
			}

			//组件挂载完毕的钩子
			componentDidMount(){
				console.log('Count---componentDidMount');
			}
			render(){
				console.log('Count---render');
				const {count} = this.state
				return(
					<div>
						<h2>当前求和为:{count}</h2>
						<button onClick={this.add}>点我+1</button>
					</div>
				)
			}
		}
		//渲染组件
		ReactDOM.render(<Count/>,document.getElementById('test'))
	</script>
</body>
</html>

在这里插入图片描述

12.2、 更新阶段

12.2.1、setState()

由组件内部this.setSate()或父组件render触发

  • shouldComponentUpdate()
  • componentWillUpdate()
  • render() =====> 必须使用的一个
  • componentDidUpdate()
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>2_react生命周期()</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入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">
		class Count extends React.Component{

			//构造器
			constructor(props){
				console.log('Count---constructor');
				super(props)
				//初始化状态
				this.state = {count:0}
			}

			//加1按钮的回调
			add = ()=>{
				//获取原状态
				const {count} = this.state
				//更新状态
				this.setState({count:count+1})
			}

			//卸载组件按钮的回调
			death = ()=>{
				ReactDOM.unmountComponentAtNode(document.getElementById('test'))
			}

			//强制更新按钮的回调
			force = ()=>{
				this.forceUpdate()
			}

			//组件将要挂载的钩子
			componentWillMount(){
				console.log('Count---componentWillMount');
			}

			//组件挂载完毕的钩子
			componentDidMount(){
				console.log('Count---componentDidMount');
			}

			//组件将要卸载的钩子
			componentWillUnmount(){
				console.log('Count---componentWillUnmount');
			}

			//控制组件更新的“阀门”
			shouldComponentUpdate(){
				console.log('Count---shouldComponentUpdate');
				return true//如果是false,后面将不会再继续执行
			}

			//组件将要更新的钩子
			componentWillUpdate(){
				console.log('Count---componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate(){
				console.log('Count---componentDidUpdate');
			}

			render(){
				console.log('Count---render');
				const {count} = this.state
				return(
					<div>
						<h2>当前求和为:{count}</h2>
						<button onClick={this.add}>点我+1</button>
					</div>
				)
			}
		}
		

		//渲染组件
		ReactDOM.render(<Count/>,document.getElementById('test'))
	</script>
</body>
</html>

在这里插入图片描述

点击点我加1
在这里插入图片描述

12.2.2、forceUpdate

强制更新,不经过阀门shouldComponentUpdate

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>2_react生命周期()</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入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">
		class Count extends React.Component{

			//构造器
			constructor(props){
				console.log('Count---constructor');
				super(props)
				//初始化状态
				this.state = {count:0}
			}

			//加1按钮的回调
			add = ()=>{
				//获取原状态
				const {count} = this.state
				//更新状态
				this.setState({count:count+1})
			}

			//卸载组件按钮的回调
			death = ()=>{
				ReactDOM.unmountComponentAtNode(document.getElementById('test'))
			}

			//强制更新按钮的回调
			force = ()=>{
				this.forceUpdate()
			}

			//组件将要挂载的钩子
			componentWillMount(){
				console.log('Count---componentWillMount');
			}

			//组件挂载完毕的钩子
			componentDidMount(){
				console.log('Count---componentDidMount');
			}

			//组件将要卸载的钩子
			componentWillUnmount(){
				console.log('Count---componentWillUnmount');
			}

			//控制组件更新的“阀门”
			shouldComponentUpdate(){
				console.log('Count---shouldComponentUpdate');
				return true
			}

			//组件将要更新的钩子
			componentWillUpdate(){
				console.log('Count---componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate(){
				console.log('Count---componentDidUpdate');
			}

			render(){
				console.log('Count---render');
				const {count} = this.state
				return(
					<div>
						<h2>当前求和为:{count}</h2>
						<button onClick={this.add}>点我+1</button>
                        <button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
					</div>
				)
			}
		}
		

		//渲染组件
		ReactDOM.render(<Count/>,document.getElementById('test'))
	</script>
</body>
</html>

在这里插入图片描述
在这里插入图片描述

12.2.3、父组件render

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>2_react生命周期()</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入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">
		//父组件A
		class A extends React.Component{
			//初始化状态
			state = {num:'11111111111111'}

			changeCar = ()=>{
				this.setState({num:'2222222222'})
			}

			render(){
				return(
					<div>
						<div>我是A组件</div>
						<button onClick={this.changeCar}>切换</button>
						<B num={this.state.num}/>
					</div>
				)
			}
		}
		
		//子组件B
		class B extends React.Component{
			//组件将要接收新的props的钩子
			componentWillReceiveProps(props){
				console.log('B---componentWillReceiveProps',props);
			}

			//控制组件更新的“阀门”
			shouldComponentUpdate(){
				console.log('B---shouldComponentUpdate');
				return true
			}
			//组件将要更新的钩子
			componentWillUpdate(){
				console.log('B---componentWillUpdate');
			}

			//组件更新完毕的钩子
			componentDidUpdate(){
				console.log('B---componentDidUpdate');
			}

			render(){
				console.log('B---render');
				return(
					<div>我是B组件,接收到的数字是:{this.props.num}</div>
				)
			}
		}
		
		ReactDOM.render(<A/>,document.getElementById('test'))
	</script>
</body>
</html>

在这里插入图片描述
在这里插入图片描述

12.3、卸载组件:

由ReactDOM.unmountComponentAtNode()触发

  1. componentWillUnmount() =====> 常用,一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息

13、生命周期函数(新)

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

  1. constructor()
  2. getDerivedStateFromProps
  3. render()
  4. componentDidMount() =====> 常用,一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息

更新阶段: 由组件内部this.setSate()或父组件重新render触发
1. getDerivedStateFromProps
2. shouldComponentUpdate()
3. render()
4. getSnapshotBeforeUpdate
5. componentDidUpdate()

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

  1. componentWillUnmount() =====> 常用,一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
    在这里插入图片描述
    在这里插入图片描述

13.1、getDerivedStateFromProps

及其罕见使用,会影响状态,若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>3_react生命周期()</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../../js/17.0.1/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../../js/17.0.1/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../../js/17.0.1/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
		class Count extends React.Component{
			/* 
				1. 初始化阶段: 由ReactDOM.render()触发---初次渲染
								1.	constructor()
								2.	getDerivedStateFromProps 
								3.	render()
								4.	componentDidMount() =====> 常用
											一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
				2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发
								1.	getDerivedStateFromProps
								2.	shouldComponentUpdate()
								3.	render()
								4.	getSnapshotBeforeUpdate
								5.	componentDidUpdate()
				3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
								1.	componentWillUnmount()  =====> 常用
											一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
			*/
			//构造器
			constructor(props){
				console.log('Count---constructor');
				super(props)
				//初始化状态
				this.state = {count:0}
			}

			//加1按钮的回调
			add = ()=>{
				//获取原状态
				const {count} = this.state
				//更新状态
				this.setState({count:count+1})
			}

			//卸载组件按钮的回调
			death = ()=>{
				ReactDOM.unmountComponentAtNode(document.getElementById('test'))
			}

			//强制更新按钮的回调
			force = ()=>{
				this.forceUpdate()
			}
			
			//若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps
			static getDerivedStateFromProps(props,state){
				console.log('getDerivedStateFromProps',props,state);
				return props
			}

			//组件挂载完毕的钩子
			componentDidMount(){
				console.log('Count---componentDidMount');
			}

			//组件将要卸载的钩子
			componentWillUnmount(){
				console.log('Count---componentWillUnmount');
			}

			//控制组件更新的“阀门”
			shouldComponentUpdate(){
				console.log('Count---shouldComponentUpdate');
				return true
			}

			//组件更新完毕的钩子
			componentDidUpdate(preProps,preState,snapshotValue){
				console.log('Count---componentDidUpdate',preProps,preState,snapshotValue);
			}
			
			render(){
				console.log('Count---render');
				const {count} = this.state
				return(
					<div>
						<h2>当前求和为:{count}</h2>
						<button onClick={this.add}>点我+1</button>
						<button onClick={this.death}>卸载组件</button>
						<button onClick={this.force}>不更改任何状态中的数据,强制更新一下</button>
					</div>
				)
			}
		}
		
		//渲染组件
		ReactDOM.render(<Count count={199}/>,document.getElementById('test'))
	</script>
</body>
</html>

getDerivedStateFromProps,后再点击按钮都不会有变化

	//若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps
			static getDerivedStateFromProps(props,state){
				console.log('getDerivedStateFromProps',props,state);
				return props
			}

在这里插入图片描述
一般要调用的话就返回null

13.2、getSnapshotBeforeUpdate

获取快照

14、diff算法

14.1、虚拟DOM中key的作用:

1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。
2). 详细的说: 当状态中的数据发生变化时,react会根据新数据生成新的虚拟DOM, 随后React进行新虚拟DOM旧虚拟DOM的diff比较,比较规则如下:

  • a. 旧虚拟DOM中找到了与新虚拟DOM相同的key:
    (1).若虚拟DOM中内容没变, 直接使用之前的真实DOM
    (2).若虚拟DOM中内容变了, 则生成新的真实DOM,随后替换掉页面中之前的真实DOM
  • b. 旧虚拟DOM中未找到与新虚拟DOM相同的key
    根据数据创建新的真实DOM,随后渲染到到页面
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>3_react生命周期()</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../../js/17.0.1/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../../js/17.0.1/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../../js/17.0.1/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
	class Person extends React.Component{
        state={
            persons:[
                {id:1,name:'小张',age:18},
                {id:2,name:'小李',age:19}
            ]
        }
        add=()=>{
            let p={id:3,name:'小王',age:20}
            let {persons}=this.state;
            this.setState({persons:[p,...persons]})
        }
        render()
        {
            return(
               <div>
                <ul>
                    {
                        this.state.persons.map((item,index)=>{
                            return <li key={index}>{item.id}-------{item.name}</li>
                        })
                    }
                </ul>
                <button onClick={this.add}>点击我添加</button>
                </div>
            )
        }
    }
		//渲染组件
		ReactDOM.render(<Person/>,document.getElementById('test'))
	</script>
</body>
</html>

在这里插入图片描述
在这里插入图片描述

14.2、使用index索引值作为key

		初始数据:
				{id:1,name:'小张',age:18},
				{id:2,name:'小李',age:19},
		初始的虚拟DOM:
				<li key=0>小张---18</li>
				<li key=1>小李---19</li>
	点击按钮添加后,添加了新数据,此时小王在数组里的下标是0了
		更新后的数据:
				{id:3,name:'小王',age:20},
				{id:1,name:'小张',age:18},
				{id:2,name:'小李',age:19},
		更新数据后的虚拟DOM:
				<li key=0>小王---20</li>
				<li key=1>小张---18</li>
				<li key=2>小李---19</li>
		和初始虚拟dom对比,找相同key,新虚拟dom里key为0的和旧虚拟dom里key为0的不相同
		,于是生成新的真实dom,替换掉页面的旧的真实dom,导致不能复用

14.3、用index作为key可能会引发的问题

  1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
    会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
  2. 如果结构中还包含输入类的DOM:会产生错误DOM更新 ==> 界面有问题。
  3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,仅用于渲染列表用于展示,使用index作为key是没有问题的。
<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>3_react生命周期()</title>
</head>
<body>
	<!-- 准备好一个“容器” -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../../js/17.0.1/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../../js/17.0.1/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../../js/17.0.1/babel.min.js"></script>

	<script type="text/babel">
		//创建组件
	class Person extends React.Component{
        state={
            persons:[
                {id:1,name:'小张',age:18},
                {id:2,name:'小李',age:19}
            ]
        }
        add=()=>{
            let p={id:3,name:'小王',age:20}
            let {persons}=this.state;
            this.setState({persons:[p,...persons]})
        }
        render()
        {
            return(
               <div>
                <ul>
                    {
                        this.state.persons.map((item,index)=>{
                            return (<li key={index}>{item.id}-------{item.name} <input type="text"/></li>)
                        })
                    }
                </ul>
                <button onClick={this.add}>点击我添加</button>
                </div>
            )
        }
    }
		//渲染组件
		ReactDOM.render(<Person/>,document.getElementById('test'))
	</script>
</body>
</html>

在这里插入图片描述
点击按钮后
在这里插入图片描述

	用index作为key初始数据:
				{id:1,name:'小张',age:18},
				{id:2,name:'小李',age:19},
		初始的虚拟DOM:
				<li key=0>小张---18<input type="text"/></li>
				<li key=1>小李---19<input type="text"/></li>
	点击按钮添加后,添加了新数据,此时小王在数组里的下标是0了
		更新后的数据:
				{id:3,name:'小王',age:20},
				{id:1,name:'小张',age:18},
				{id:2,name:'小李',age:19},
		更新数据后的虚拟DOM:
				<li key=0>小王---20<input type="text"/></li>
				<li key=1>小张---18<input type="text"/></li>
				<li key=2>小李---19<input type="text"/></li>
一层一层对比,一层一层找,发现input标签是相同的,就不会生成新的真实dom
				直接复用

使用id唯一标识作为key

		初始数据:
				{id:1,name:'小张',age:18},
				{id:2,name:'小李',age:19},
		初始的虚拟DOM:
				<li key=1>小张---18<input type="text"/></li>
				<li key=2>小李---19<input type="text"/></li>

		更新后的数据:
				{id:3,name:'小王',age:20},
				{id:1,name:'小张',age:18},
				{id:2,name:'小李',age:19},
		更新数据后的虚拟DOM:
				<li key=3>小王---20<input type="text"/></li>
				<li key=1>小张---18<input type="text"/></li>
				<li key=2>小李---19<input type="text"/></li>

		旧虚拟DOM中找不到到了与新虚拟DOM相同的key=3,会生成新的真实dom
		后面对比key=1的,内容相同,可以复用。

14.4、开发中如何选择key?:

1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果确定只是简单的展示数据,用index也是可以的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React学习路线图是一个指导学习React的图表,它提供了一条学习React所需的知识和技能的路径。这个路线图包括了React的基础知识和重要概念,以及一些额外的学习资源和库。你可以使用这个路线图作为学习React的指南,帮助你更好地了解React学习路径和学习顺序。如果你对React完全不了解,我建议你先阅读React的入门教程,例如React官方推荐的入门教程《React入门教程 – 概述和实际演练》和2018年学习React.js的综合指南。这些教程将介绍React的基本概念和实践,帮助你建立起对React的基本理解。之后,你可以根据React开发者线路图中的学习路径,逐步深入学习React的相关知识和技能。这个路线图将指导你学习React的核心部分和重要的知识点,以及一些额外的学习资源和库,帮助你更好地成为一名React开发人员。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [(转)2019年 React 新手学习指南 – 从 React 学习线路图说开去](https://blog.csdn.net/weixin_30544657/article/details/101470289)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值