1 React 入门
1 React 简介
2 hello_React.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello_react</title>
</head>
<body>
<!--1 准备容器-->
<div id="test"></div>
<!--2-1 引入React 核心库-->
<script type="text/javascript" src="../js/react.development.js"></script>
<!--2-2 引入React-dom. 用于支持React操作DOM-->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!--2-3 引入 babel. 将jsx转为js-->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">/* 此处一定要写babel,因为我们写jsx */
// 3-1 创建虚拟dom
const VDOM = <h1>hello,react</h1>/*这里不用写引号,因为是jsx,不是字符串*/
// 3-2 渲染虚拟dom 到页面/* ReactDOM.render(虚拟dom,容器) */
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
</body>
</html>
3 虚拟dom与真实dom
关于虚拟dom:
- 1 本质是Object 类型对象(一般对象)
- 2 虚拟dom 轻,真实dom重,因为虚拟dom是React内部在用,无需真实dom上那么多的属性
- 3 虚拟dom最终会被React转换为真实dom,呈现在界面上
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>虚拟dom与真实dom</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" > /* 此处一定要写babel */
//1.创建虚拟DOM
const VDOM =(/* 此处一定不要写引号,因为不是字符串 */
<h1 id="title">
<span>Hello,React</span>
</h1>)
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
console.log('虚拟dom',VDOM)
const TDOM = document.getElementById('demo')
console.log('真实dom',TDOM)
// debugger
// console.log(typeof VDOM)
// console.log(VDOM instanceof Object )
</script>
</body>
</html>
4 jsx语法规则
json 存储方法好用
- parse ::将json字符串解析为js的对象、数组
- stringfy :将js的对象、数组解析为json字符串
jsx语法规则:
1 这里不用写引号,因为是jsx,不是字符串
2 标签中混入js表达式用{}
3 样式的类名指定为className
4 内联样式,用style={{key:value}}
5 只有一个根标签
6 标签必须闭合
7 标签首字母
- 如小写字母开头,这jsx转为html,若html标签无对应,则报错
- 若大写字母开头,则React就去渲染对应的组件,若组件没有定义,就保存
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> jsx语法规则</title>
<style>
.title{
background-color: burlywood;
width: 200px;
}
</style>
</head>
<body>
<!--1 准备容器-->
<div id="test" ></div>
<!--2-1 引入React 核心库-->
<script type="text/javascript" src="../../js/react.development.js"></script>
<!--2-2 引入React-dom. 用于支持React操作DOM-->
<script type="text/javascript" src="../../js/react-dom.development.js"></script>
<!--2-3 引入 babel. 将jsx转为js-->
<script type="text/javascript" src="../../js/babel.min.js"></script>
<script type="text/babel">/* 此处一定要写babel,因为我们写jsx */
const myId = 'JulY'
const myData = 'heLLO, reAct'
// 3-1 创建虚拟dom
const VDOM = (
<div>
<h2 className="title" id={myId.toLowerCase()}>
<span style={{color:'pink',fontsize:'29px'}}> {myData.toUpperCase()}</span>
</h2>
<h2 className="title" id={myId.toLowerCase()}>
<span style={{color:'pink',fontsize:'29px'}}> {myData.toUpperCase()}</span>
</h2>
<input type="text"/>
</div>
)
// 3-2 渲染虚拟dom 到页面/* ReactDOM.render(虚拟dom,容器) */
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
</body>
</html>
5 js表达式 vs js语句
注意区分 : js表达式 vs js语句
- 下面都是表达式:
- a
- a+b
- demo(1)
- arr.map()
- function test(){}
- 下面是语句:
- for(){}
- if(){}
- switch(){}
<!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" >
//3 模拟一些数据
const data = ['Angular','react','vue']
// 1 创建虚拟dom
const VDOM =(
<div>
<h1>前端js框架列表</h1>
<ul>
{
//4 js表达式
data.map((item,index)=>{
return <li key={index}>{item}</li>
})
}
</ul>
</div>
)
// 2 渲染虚拟dom到页面
ReactDOM.render(VDOM, document.getElementById('test'))
</script>
</body>
</html>
2 React 面向组件化编程
1 函数式组件
执行了 ReactDOM.render(....后,发生了什么?
- 1 React 解析组件标签,找到MyComponent组件
- 2 发现组件是函数式定义的,随后调用该函数,将返回的虚拟dom转为真实dom,随后呈现在页面中
<!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">
// 1 函数函数式组件
function MyComponet() {
console.log(this)//此处this 是undefined,因为babel编译后开启了严格模式
return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
}
//2 渲染组件到页面
ReactDOM.render(<MyComponet/>, document.getElementById('test'))
/*
* */
</script>
</body>
</html>
1.5 class 复习
- 类中的构造器不是必须写,要对实例进行一些初始化操作,如添加特定属性
- 如果A类 extend B类,且A类中写了构造器,那么A类构造器中的super()必须调用
- 类中所定义的方法,都是放在类的原型对象上,供实例使用
//1 创建一个Person的类
class Person {
//3 构造器方法
constructor(name,age) {
// 构造器中this是 ——类的实例对象
this.name = name
this.age = age
}
//一般方法
say(){
//say方法放在--类的原型对象上,给实例用
//通过Person实例调用say(),say中this就是Person实例
console.log(`我叫${this.name},年龄是${this.age}`)
}
}
//2 创建一个Person的实例对象
const p1 = new Person('tom',12)
const p2 = new Person('lily',14)
console.log(p1)//Person { name: 'tom', age: 12 }
console.log(p2)//Person { name: 'lily', age: 14 }
p1.say()//我叫tom,年龄是12
p2.say()//我叫lily,年龄是14
p1.say.call({a:1,b:2})//call apply 等方法可以更改this指向,我叫undefined,年龄是undefined
// 4 创建一个Student类,继承 与Person类
class Student extends Person{
constructor(name ,age,grade) {
super(name,age);
this.grade = grade
}
say() {
//重写继承的say方法
console.log(`我叫${this.name},年龄是${this.age},年级是${this.grade}`)
}
study(){
//study方法放在--类的原型对象上,给实例用
//通过Student实例调用study(),study中this就是Student实例
console.log('study hard')
}
}
const s1 = new Student('sam',15,'高一')
console.log(s1)//Student { name: 'sam', age: 15, grade: '高一' }
s1.say()//我叫sam,年龄是15,年级是高一
2 类式组件
- 执行了 ReactDOM.render(....后,发生了什么?
-
1 React 解析组件标签,找到MyComponent组件
-
2 发现组件是类定义的,随后new出来该类实例,并通过该实例调用到原型上的render方法
-
3 将返回的虚拟dom转为真实dom,随后呈现在页面中
-
-
render方法放在了哪里?——MyCompnont的原型对象上,供实例使用
-
render 中this是?——MyCompnont的实例对象==MyCompnont组件实例对象
<!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">
// 1 创建类式组件
class MyCompnont extends React.Component{
render() {
//render方法放在了哪里?——MyCompnont的原型对象上,供实例使用
//render 中this是?——MyCompnont的实例对象==MyCompnont组件实例对象
console.log('render中this是:',this)//render中this是: MyCompnont
return (
<h2>我是用函数定义的组件(适用于【复杂组件】的定义)</h2>
);
}
}
//2 渲染组件到页面
ReactDOM.render(<MyCompnont/>, document.getElementById('test'))
/*
* 执行了 ReactDOM.render(<MyComponet/>....后,发生了什么?
* 1 React 解析组件标签,找到MyComponent组件
* 2 发现组件是类定义的,随后new出来该类实例,并通过该实例调用到原型上的render方法
* 3 将返回的虚拟dom转为真实dom,随后呈现在页面中
* */
</script>
</body>
</html>
3 state --组件实例的三大核心属性之一
state是组件对象最重要的属性,值是对象
组件被称为状态机,通过更新组件的state,来重新渲染组件
-
注
- 组件中render方法中this 为组件实例对象
- 组件自定义方法中this 为 undefined,用bind()强制绑定this;or 箭头函数 + 赋值语句
- 状态数据不能直接更新,用 setState
-
原生事件绑定的三种方式
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<button id="btn1">1</button>
<button id="btn2">2</button>
<button onclick="demo()">3</button><!-- way 3,推荐使用-->
<script type="text/javascript">
// way 1
const btn1 = document.getElementById('btn1')
btn1.addEventListener('click',()=>{
alert('按钮1被点击')
})
// way 2
const btn2 = document.getElementById('btn2')
btn1.onclick=()=>{
alert('按钮2被点击')
}
// way 3,推荐使用
function demo(){
alert('按钮3被点击')
}
</script>
</body>
</html>
React事件绑定的方法
- step 1
*这里注意 onClick 和{changeWeather}
- 点击事件 在js中是onclick;在React中是onClick
- {changeWeather}里面不能写{changeWeather()}这里changeWeather加了()就是回调了changeWeather,这里只需要有此函数即可,回调在点击后才显示
<!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">
let that
//1 创建组件
class Weather extends React.Component{
//1-1 构造器
constructor(props) {
super(props);
//1-2初始化状态
this.state = {isHot:false}
that = this//1-3缓存this
}
render() {
//1-3 读取状态
const {isHot} = this.state
console.log(this)//Render 这里的this就是weather的实例对象
return (
// <h1 id="title">今天天气很{isHot?'热':'凉'}</h1>
<h1 onClick={changeWeather}>今天天气很{isHot?'热':'凉'}</h1>
);
}
}
//2 渲染组件
ReactDOM.render(<Weather/>, document.getElementById('test'))
// 2-1 添加点击事件
//way 2-1-3
function changeWeather() {
console.log('此处修改isHot')
// const {isHot} = this.state.isHot//这里的this是undefined,因为babel是「use strict」严格模式,识别这里是独立的函数
console.log(that.state.isHot)
}
}
</script>
</body>
</html>
类方法中的this: 类中开了局部的严格模式,this是undefined
class Person{
constructor(name,age) {
this.name = name
this.age = age
}
speak(){
//speak 放在? Person 的原型对象上,供实例使用
//通过 Person 实例调用speak时,speak中的this就是 Person 的实例
console.log(this)
}
}
const p1 = new Person('tom',12)
p1.speak()//通过实例调用speak
const x = p1.speak
x()// ,此处是函数直接调用speak
// undefined 类中开了局部的严格模式,this就是undefined
- step 2
<!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 {
//1-1 构造器
constructor(props) {
super(props);
//1-2初始化状态
this.state = {isHot: false}
}
render() {
//1-3 读取状态
const {isHot} = this.state//Render 这里的this就是weather的实例对象
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '热' : '凉'}</h1>
}
// 2-1 添加点击事件
changeWeather() {
//changeWeather 放在? weather的原型对象上,供实例使用
//通过Weather实例调用changeWeather时,changeWeather中的this就是Weather的实例
console.log(this.state.isHot)
}
}
//2 渲染组件
ReactDOM.render(<Weather/>, document.getElementById('test'))
</script>
</body>
</html>
- step 3
<!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 {
//1-1 构造器
constructor(props) {
super(props);
//1-2初始化状态
this.state = {isHot: false}
}
render() {
//1-3 读取状态
const {isHot} = this.state//Render 这里的this就是weather的实例对象
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '热' : '凉'}</h1>
}
// 2-1 添加点击事件
changeWeather() {
//changeWeather 放在? weather的原型对象上,供实例使用
//由于 changeWeather 是作为onClick的回调,所以不是通过实例调用的,是直接调用,
// 类中方法默认开启局部的 严格模式,所以 changeWeather 中的this是undefined
console.log(this)
}
}
//2 渲染组件
ReactDOM.render(<Weather/>, document.getElementById('test'))
</script>
</body>
</html>
解决类中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 {
//1-1 构造器
constructor(props) {
super(props);
//1-2初始化状态
this.state = {isHot: false}
//解决 changeWeather this 指向问题
this.changeWeather = this.changeWeather.bind(this)//bind可以 1 生成新函数; 2 改变this指向
}
render() {
//1-3 读取状态
const {isHot} = this.state//Render 这里的this就是weather的实例对象
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '热' : '凉'}</h1>
}
// 2-1 添加点击事件
changeWeather() {
//changeWeather 放在? weather的原型对象上,供实例使用
//由于 changeWeather 是作为onClick的回调,所以不是通过实例调用的,是直接调用,
// 类中方法默认开启局部的 严格模式,所以 changeWeather 中的this是undefined
console.log(this)
}
}
//2 渲染组件
ReactDOM.render(<Weather/>, document.getElementById('test'))
</script>
</body>
</html>
setState
<!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 {
//1-1 构造器 ,调用几次? ———— 1次
constructor(props) {
super(props);
//1-2初始化状态
this.state = {isHot: false,wind:'微风'}
//解决 changeWeather this 指向问题
this.changeWeather = this.changeWeather.bind(this)//bind可以 1 生成新函数; 2 改变this指向
}
//rander 调用几次? 1+n 次,1 是 初始化那次, n 是更新次数
render() {
//1-3 读取状态
const {isHot,wind} = this.state//Render 这里的this就是weather的实例对象
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '热' : '凉'},{wind}</h1>
}
// 1-4 添加点击事件
//changeWeather 调用几次? 点击几次调用几次
changeWeather() {
//changeWeather 放在? weather的原型对象上,供实例使用
//由于 changeWeather 是作为onClick的回调,所以不是通过实例调用的,是直接调用,
// 类中方法默认开启局部的 严格模式,所以 changeWeather 中的this是undefined
//获取原来的isHot值
const isHot = this.state.isHot
this.setState({isHot:!isHot})// !!! state 通过 setState 更改,且更新是同名更改,合并,不是替换
// this.state.isHot = !isHot // !!! : state 不可以直接更改,这句是错误的,是直接更改
}
}
//2 渲染组件ReactDOM.render(<Weather/>, document.getElementById('test'))
</script>
</body>
</html>
state的简写方式(开发)
<!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 = () =>{//箭头函数没有自己的this,是外侧的this,即 Weather 的实例对象
const isHot = this.state.isHot
this.setState({isHot:!isHot})
}
}
//2 渲染组件到页面
ReactDOM.render(<Weather/>, document.getElementById('test'))
</script>
</body>
</html>
4 props --组件实例的三大核心属性之一
props 是通过标签属性从组件外部相组件内部传递 变化的数据
注意 组件内部不要修改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>
<!-- 引入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 Person extends React.Component {
render() {
const {name,age,gender} = this.props//解构赋值
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{gender}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
//渲染组件到页面
ReactDOM.render(<Person name='tom' age='17' gender='man'/>, document.getElementById('test1'))
</script>
</body>
</html>
...展开运算符(复习)
用法:
- 展开一个数组
- 连接两个数组
- 函数传参
- 复制对象(构造字面量时使用展开语法)
- 负责对象同时修改属性,合并 注:let clonePerson = {...Person}//可以克隆一个对象,字面量对象,注意不能与React中{...p}相提并论,react里即...p
let arr1 = [1,3,4,5,6]
let arr2 = [2,3,57,8,9]
//展开一个数组
console.log(...arr1)//1 3 4 5 6
//连接数组
let arr3 = [...arr1,...arr2]
console.log(arr3)//(10) [1, 3, 4, 5, 6, 2, 3, 57, 8, 9]
//函数传参
function sum(...args) {
return args.reduce((pre,cur)=>{
return pre + cur
})
}
console.log(sum(1,23,4))
//构造字面量时使用展开语法
let Person = {name:'sam',age:'24'}
// console.log(...Person)//报错,展开运算符不能展开对象
let clonePerson = {...Person}//可以克隆一个对象,字面量对象,注意不能与React中{...p}相提并论,react里即...p
console.log(clonePerson)
//负责对象同时修改属性,合并
let person3 = {...Person,name:'jack',address:'house'}
console.log(person3)
批量传递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>
<script type="text/babel">
//创建组件
class Person extends React.Component {
render() {
const {name,age,gender} = this.props//解构赋值
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{gender}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
//渲染组件到页面
ReactDOM.render(<Person name='tom' age='17' gender='man'/>, document.getElementById('test1'))
ReactDOM.render(<Person name='sam' age='18' gender='man'/>, document.getElementById('test2'))
const p = {name:'lily',age:'19',gender:'female'}
console.log('@',...p)
ReactDOM.render(<Person{...p}/>, document.getElementById('test3'))//展开运算符... 不能展开对象
</script>
</body>
</html>
对props 进行限制
this.props.name = 'jack' //会报错 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 {
render() {
const {name,age,gender} = this.props//解构赋值
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{gender}</li>
<li>年龄:{age+1}</li>
</ul>
)
}
}
//对标签属性进行类型和必要性的限制 Person.属性规则
Person.propTypes = {
name:PropTypes.string.isRequired,//注意这里string,是小写的
gender:PropTypes.string,//限制性别是字符串
age:PropTypes.number,
speak:PropTypes.func //限制speak是函数,
}
//指定默认标签属性值
Person.defaultProps = {
gender:'不告知',
age:18
}
//渲染组件到页面
ReactDOM.render(<Person name='tom' age={17} gender='man'/>, document.getElementById('test1'))
ReactDOM.render(<Person name='sam' speak={speak} gender='man'/>, document.getElementById('test2'))
const p = {name:'lily',age:19,gender:'female'}
ReactDOM.render(<Person{...p}/>, document.getElementById('test3'))//展开运算符... 不能展开对象
function speak() {
console.log('ok')
}
</script>
</body>
</html>
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 {
static propTypes = {
name:PropTypes.string.isRequired,//注意这里string,是小写的
gender:PropTypes.string,//限制性别是字符串
age:PropTypes.number,
speak:PropTypes.func //限制speak是函数,
}
//指定默认标签属性值
static defaultProps = {
gender:'male',
age:18
}
render() {
const {name,age,gender} = this.props//解构赋值
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{gender}</li>
<li>年龄:{age+1}</li>
</ul>
)
}
}
//对标签属性进行类型和必要性的限制 Person.属性规则
//渲染组件到页面
ReactDOM.render(<Person name='tom' age={17} gender='man'/>, document.getElementById('test1'))
ReactDOM.render(<Person name='sam' speak={speak} gender='man'/>, document.getElementById('test2'))
const p = {name:'lily',age:19,gender:'female'}
ReactDOM.render(<Person{...p}/>, document.getElementById('test3'))//展开运算符... 不能展开对象
function speak() {
console.log('ok')
}
</script>
</body>
</html>
类式组件中的构造器与props
- construct(props)
通常在React中 construct函数有两种情况:
- 1 通过给this。state赋值对象来初始化内部state
- 2 为事件处理函数绑定实例
函数式组件使用props
由于函数本身能够穿参数,因此可以传props
但函数式组件只能使用props ,不能使用state 和 refs
<!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">
//创建组件
function Person(props) {
const {name,age,gender} = props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{gender}</li>
<li>年龄:{age}</li>
</ul>
)
}
Person.propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串
gender:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
}
//指定默认标签属性值
Person.defaultProps = {
gender:'男',//sex默认值为男
age:18 //age默认值为18
}
//渲染组件到页面
ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
</script>
</body>
</html>
5 refs与事件处理 --组件实例的三大核心属性之一
相当于原始js 里的 id 就是打标签
字符串形式的ref(不推荐)
效率不高哦,已过时
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1_字符串形式的ref</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 Demo extends React.Component {
//展示左侧输入框数据
showData = ()=>{
const {input1} = this.refs
alert(input1.value)
}
//展示右侧输入框数据
showData2 = ()=>{
//函数体
const {input2} = this.refs
alert(input2.value)
}
render() {
return (
<div>
<input ref='input1' type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点我提示左侧数据</button>
<input ref="input2" onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo a="1" b="2" />, document.getElementById('test'))
</script>
</body>
</html>
回调形式的ref
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1_字符串形式的ref</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 Demo extends React.Component {
//展示左侧输入框数据
showData = ()=>{
const {input1} = this
alert(input1.value)
}
//展示右侧输入框数据
showData2 = ()=>{
//函数体
const {input2} = this
alert(input2.value)
}
render() {
return (
<div>
<input ref={currentNode=>this.input1 = currentNode} type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点我提示左侧数据</button>
<input onBlur={this.showData2} ref={currentNode=>this.input2 = currentNode} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo a="1" b="2" />, document.getElementById('test'))
</script>
</body>
</html>
回调ref中回调执行次数的问题
回调ref以 内联函数的方式展示,在更新的过程中会被执行 2 次,第一传入的是 Null ,第二次传入的参数是 DOM 元素(这个可以有)
用 class 方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>3_回调ref中回调执行次数的问题</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 Demo extends React.Component {
state = {isHot:false}
changeWeather = ()=>{
//获取原来的状态
const {} = this.state
//更新状态
this.state({isHot :!isHot })
}
showInfo = ()=>{
const {input1} =this
alert(input1.value)
}
saveInput = (c)=>{
this.input1 = c
console.log('@',c)
}
render() {
const {isHot} = this.state
return (
<div>
<h2>今天天气很{isHot ? 'hot':'cold'}</h2>
{/*<input ref={c => {this.input1=c;console.log('@',c)}} type="text"/><br/><br/>*/}
<input ref={this.saveInput} type="text"/>
<button onClick={this.showInfo}>点我显示输入的数据</button> <br/><br/>
<button onClick={this.changeWeather}>点我切换天气</button>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo/>,document.getElementById('test'))
</script>
</body>
</html>
createRef
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>4_createRef</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 Demo extends React.Component {
/*React。createRef()调用后可以返回一个容器,该容器可以存储被ref所标识的节点*/
myRef1 = React.createRef()
//展示左侧输入框数据
showData = ()=>{
alert(this.myRef1.current.value)
}
render() {
return (
<div>
<input ref={this.myRef1} type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点我提示左侧数据</button>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo a="1" b="2" />, document.getElementById('test'))
</script>
</body>
</html>
6 React事件处理
-
(1).通过onXxx属性指定事件处理函数(注意大小写)
- a.React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —————— 为了更好的兼容性
- b.React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————————为了的高效(冒泡)
-
(2).通过event.target得到发生事件的DOM元素对象 ——————————不要过度使用ref
-
不要过度使用ref:当 发送事件是 自己 要操作的事件,可以不用ref ,用event.target.value
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>事件处理</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 Demo extends React.Component{
/*
(1).通过onXxx属性指定事件处理函数(注意大小写)
a.React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —————— 为了更好的兼容性
b.React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ————————为了的高效
(2).通过event.target得到发生事件的DOM元素对象 ——————————不要过度使用ref
*/
//创建ref容器
myRef = React.createRef()
myRef2 = React.createRef()
//展示左侧输入框的数据
showData = (event)=>{
alert(this.myRef.current.value);
}
//展示右侧输入框的数据
showData2 = (event)=>{
alert(event.target.value);
}
render(){
return(
<div>
<input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点我提示左侧的数据</button>
<input onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo a="1" b="2"/>,document.getElementById('test'))
</script>
</body>
</html>
7 React 收集表单数据
非受控组件
页面中所有输入型的组件,现用现取的,就是非受控组件
<!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 Login extends React.Component {
handleSubmit = (event)=>{
event.preventDefault()//阻止表单提交
const {username,password} = this
alert(`用户名是${username.value},密码是${password.value}`)
}
render() {
return (
<form action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
用户名:<input ref={c => this.username =c} type="text" name="username"/><br/>
密码: <input ref={c => this.password =c} type="text" name="password"/><br/>
<button>登录</button>
</form>
)
}
}
//渲染组件
ReactDOM.render(<Login/>, document.getElementById('test'))
</script>
</body>
</html>
受控组件--推荐使用
页面中所有输入型的组件,维护状态到setState(即vue中的双向绑定), 去掉了ref
<!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 action="http://www.atguigu.com" onSubmit={this.handleSubmit}>
用户名:<input onChange={this.saveUsername} type="text" name="username"/><br/>
密码: <input onChange={this.savePassword} type="text" name="password"/><br/>
<button>登录</button>
</form>
)
}
}
//渲染组件
ReactDOM.render(<Login/>, document.getElementById('test'))
</script>
</body>
</html>
8 组件的生命周期
生命周期回调函数 、生命周期钩子函数、生命周期函数、生命周期钩子
<!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}
blank = ()=>{
//卸载组件
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
// componentDidMount 调用时机:组件挂载完毕(只调用一次)
componentDidMount(){
this.timer = setInterval(()=>{
//初始化 透明度
let {opacity} = this.state
// 初始化减少0.1
opacity -= 0.1
if (opacity <= 0) {
opacity = 1
}
//设置新的透明度
this.setState ({opacity})
},200)
}
// 组件将要卸载 componentWillUnmount
componentWillUnmount(){
//清除定时器
clearInterval(this.timer)
}
// render 调用时机:初始化渲染,状态更新之后
render() {
return (
<div>
<h2 style={{opacity: this.state.opacity}}>天很透明</h2>
<button onClick={this.blank}>是的</button>
</div>
)
}
}
//渲染组件
ReactDOM.render(<Life/>, document.getElementById('test'))
</script>
</body>
</html>
组件挂载流程(旧)(完成上图左侧)
<!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>当前求和为</h2>
<button onClick={this.add}>点我+1</button>
</div>
)
}
}
//渲染组件
ReactDOM.render(<Count/>, document.getElementById('test'))
</script>
</body>
</html>
setState流程
正常更新流程(打开 控制组件更新的阀门)
<!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})
}
//卸载组件按钮的回调
finish=()=>{
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
//组件将要挂载钩子
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.finish}>完成</button>
</div>
)
}
}
//渲染组件
ReactDOM.render(<Count/>, document.getElementById('test'))
</script>
</body>
</html>
forceUpdate流程
强制更新路径
不更改任何状态中的数据,强制更新,
<!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})
}
//卸载组件按钮的回调
finish=()=>{
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.finish}>完成</button>
<button onClick={this.force}>不更改任何状态中的数据,强制更新</button>
</div>
)
}
}
//渲染组件
ReactDOM.render(<Count/>, document.getElementById('test'))
</script>
</body>
</html>
父组件render流程
注意这里的
componentWillReceiveProps实际上应该是componentWillReceiveNewProps
<!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 A extends React.Component {
//初始化状态
state = {carName:'benz'}
changeCar = ()=>{
this.setState({carName:'BMW'})
}
render() {
return (
<div>
<div>我是A父组件</div>
<button onClick={this.changeCar}> 换车</button>
<B carName={this.state.carName}/>
</div>
)
}
}
class B extends React.Component {
componentDidMount(){
console.log('b-componentDidMount')
}
//组件将要介绍新的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-rander')
return (
<div>我是B子组件,接收的车是:{this.props.carName}</div>
)
}
}
//渲染组件
ReactDOM.render(<A/>, document.getElementById('test'))
</script>
</body>
</html>
总结生命周期(旧)
-
- 初始化阶段: 由ReactDOM.render()触发---初次渲染
- constructor()
- componentWillMount()
- render()
- componentDidMount() =====> 常用 一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
- 初始化阶段: 由ReactDOM.render()触发---初次渲染
-
- 更新阶段: 由组件内部this.setSate()或父组件render触发
- shouldComponentUpdate()
- componentWillUpdate()
- render() =====> 必须使用的一个
- componentDidUpdate()
- 更新阶段: 由组件内部this.setSate()或父组件render触发
-
- 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
-
componentWillUnmount() =====> 常用 一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
-
- 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
getDerivedStateFromProps
若state的值在任何时候都取决于props,那么可以使用getDerivedStateFromProps,静态方法
getSnapshotBeforeUpdate
<!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{
//构造器
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 null
}
//在更新之前获取快照
getSnapshotBeforeUpdate(){
console.log('getSnapshotBeforeUpdate');
return 'atguigu'
}
//组件挂载完毕的钩子
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>
总结 新 生命周期
-
- 初始化阶段: 由ReactDOM.render()触发---初次渲染
-
- constructor()
-
- getDerivedStateFromProps
-
- render()
-
- componentDidMount() =====> 常用 一般在这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
-
- 更新阶段: 由组件内部this.setSate()或父组件重新render触发
-
- getDerivedStateFromProps
-
- shouldComponentUpdate()
-
- render()
-
- getSnapshotBeforeUpdate
-
- componentDidUpdate()
-
- 卸载组件: 由ReactDOM.unmountComponentAtNode()触发
-
- componentWillUnmount() =====> 常用 一般在这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
9 虚拟 DOM 和 DOM diff 算法
验证diff算法
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>验证diff算法</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 Time extends React.Component {
state = {date: new Date()}
componentDidMount () {
setInterval(() => {
this.setState({
date: new Date()
})
}, 1000)
}
render () {
return (
<div>
<h1>hello</h1>
<input type="text"/>
<span>
现在是:{this.state.date.toTimeString()}
<input type="text"/>
</span>
</div>
)
}
}
ReactDOM.render(<Time/>,document.getElementById('test'))
</script>
</body>
</html>
经典面试题:
- 1). react/vue中的key有什么作用?(key的内部原理是什么?)
- 2). 为什么遍历列表时,key最好不要用index?
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,随后渲染到到页面
2. 用index作为key可能会引发的问题:
1. 若对数据进行:逆序添加、逆序删除等破坏顺序操作:
会产生没有必要的真实DOM更新 ==> 界面效果没问题, 但效率低。
2. 如果结构中还包含输入类的DOM:
会产生错误DOM更新 ==> 界面有问题。
3. 注意!如果不存在对数据的逆序添加、逆序删除等破坏顺序操作,
仅用于渲染列表用于展示,使用index作为key是没有问题的。
3. 开发中如何选择key?:
1.最好使用每条数据的唯一标识作为key, 比如id、手机号、身份证号、学号等唯一值。
2.如果确定只是简单的展示数据,用index也是可以的。
慢动作回放----使用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>
更新后的数据:
{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>
-----------------------------------------------------------------
慢动作回放----使用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> (复用)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>key的作用</title>
</head>
<body>
<div id="test"></div>
<!-- 引入react核心库 -->
<script type="text/javascript" src="../js/react.development.js"></script>
<!-- 引入react-dom -->
<script type="text/javascript" src="../js/react-dom.development.js"></script>
<!-- 引入babel -->
<script type="text/javascript" src="../js/babel.min.js"></script>
<script type="text/babel">
class Person extends React.Component {
state = {
persons:[
{id:1,name:'leo',age:18},
{id:2,name:'lily',age:15},
{id:3,name:'tom',age:17},
]
}
add=()=>{
const {persons} = this.state
const p = {id:persons.length+1,name:'jerry',age:20 }
this.setState ({persons:[p,...persons]})
}
render() {
return (
<div>
<h2>展示人员信息</h2>
<button onClick={this.add}>添加</button>
<h3>使用index作为key</h3>
<ul>
{
this.state.persons.map((personObj,index)=>{
return <li key={index}>{personObj.name}---{personObj.age} <input type="text"/></li>
})
}
</ul>
<hr/><hr/>
<h3>使用id作为key</h3>
<ul>
{
this.state.persons.map((personObj,)=>{
return <li key={personObj.id}>{personObj.name}---{personObj.age}<input type="text"/></li>
})
}
</ul>
</div>
)
}
}
ReactDOM.render(<Person/>,document.getElementById('test'))
</script>
</body>
</html>