一、基础准备
二、代码练习
使用vscode
- 创建虚拟DOM
- 渲染虚拟DOM到页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>hello_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" > /* 一定要写babel */
//1.创建虚拟DOM
const VDOM = <h1>Hello,React</h1> /* 一定不要写引号,因为不是字符串 */
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
</body>
运行结果
出现这个警告是因为此时写的不是js,是jsx,并不标准,需要babel翻译成js,当代码量大了之后,就会出现问题,解决办法是用开发者工具开发。
注:此时无需处理此告警
虚拟DOM两种创建方式
- 使用jsx创建
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用jsx创建虚拟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" >
//1.创建虚拟DOM
const VDOM = ( /* 不要写引号,因为不是字符串 */
<h1 id="title">
<span>Hello,React</span>
</h1>
)
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
</body>
</html>
- 使用js创建
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>使用js创建虚拟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>
<script type="text/javascript" >
//1.创建虚拟DOM
const VDOM = React.createElement('h1',{id:'title'},React.createElement('span',{},'Hello!'))
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
</body>
</html>
总结:jsx创建虚拟DOM更加方便
虚拟DOM与真实DOM
- 本质是Object类型的对象(一般对象)。
- 虚拟DOM属性少,真实DOM属性多,因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性。
- 虚拟DOM最终会被React转化为真实DOM,呈现在页面上。
三、JSX语法规则
jsx是js的扩展语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jsx语法规则</title>
<style>
.title{
background-color: orange;
width: 200px;
}
</style>
</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 myId = 'test'
const myData = 'HeLlo'
//1.创建虚拟DOM
const VDOM = (
// 只有一个根标签
<div>
<h2 className="title" id={myId.toLowerCase()}>
<span style={{color:'white',fontSize:'24px'}}>{myData.toLowerCase()}</span>
</h2>
<h2 className="title" id={myId.toUpperCase()}>
<span style={{color:'red',fontSize:'28px'}}>{myData.toLowerCase()}</span>
</h2>
<input type="text"/>
</div>
)
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
/*
jsx语法规则:
1.定义虚拟DOM时,不要写引号。
2.标签中混入JS表达式时要用{}。
3.样式的类名指定不要用class,要用className。
4.内联样式,要用style={{key:value}}的形式去写。
5.只有一个根标签
6.标签必须闭合
7.标签首字母
(1).若小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错。
(2).若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。
*/
</script>
</body>
</html>
区分:【js语句(代码)】与【js表达式】
1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
下面这些都是表达式:
(1). a
(2). a+b
(3). demo(6)
(4). arr.map()
(5). function add() {}
2.语句(代码):
下面这些都是语句(代码):
(1).if(){}
(2).for(){}
(3).switch(){case:xxxx}
四、组件状态
组件状态:组件可以自己维护的数据
组件状态仅在类组件中有用
状态本质上是类组件上的一个属性,是一个对象
状态初始化
状态的变化
不能直接改变状态:因为React无法监控到状态发生了变化
必须使用this.setState({})改变状态
一旦调用了this.setState,会导致当前组件重新渲染
组件中的数据
- props:该数据是由组件的使用者传递的数据,所有权不属于组件自身,因此组件无法改变该数组
- state:该数组是由组件自身创建的,所有权属于组件自身,因此组件有权改变该数据
//计时器,用作倒计时
import React, { Component } from 'react'
export default class Tick extends Component {
//初始化状态,JS Next 语法,目前处于实验阶段
state = {
left: this.props.number,
n: 123
}
constructor(props) {
super(props);
//初始化状态
// this.state = {
// left: this.props.number
// };
this.timer = setInterval(() => {
this.setState({
left: this.state.left - 1
}); //重新设置状态,触发自动的重新渲染
if (this.state.left === 0) {
//停止计时器
clearInterval(this.timer);
}
}, 1000);
}
render() {
return (
<>
<h1>
倒计时剩余时间:{this.state.left}
</h1>
<p>
{this.state.n}
</p>
</>
)
}
}
五、组件事件
在React中,组件的事件,本质上就是一个属性
按照之前React对组件的约定,由于事件本质上是一个属性,因此也需要使用小驼峰命名法
如果没有特殊处理,在事件处理函数中,this指向undefined
使用bind函数,绑定this
import React, { Component } from 'react'
import Tick from "./Tick"
export default class TickControl extends Component {
state = {
isOver: false //倒计时是否完成
}
// 结果:handleClick不在原型上,而在对象上
handleClick = () => {
console.log(this)
console.log("点击了")
}
handleOver = () => {
this.setState({
isOver: true
})
}
render() {
let status = "正在倒计时";
if (this.state.isOver) {
status = "倒计时完成";
}
return (
<div>
<Tick
onClick={this.handleClick.bind(this)}
onOver={this.handleClick.bind(this)}
number={10} />
<h2>
{status}
</h2>
</div>
)
}
}
使用箭头函数
import React, { Component } from 'react'
import Tick from "./Tick"
export default class TickControl extends Component {
state = {
isOver: false //倒计时是否完成
}
// 结果:handleClick不在原型上,而在对象上
handleClick = () => {
console.log(this)
console.log("点击了")
}
handleOver = () => {
this.setState({
isOver: true
})
}
render() {
let status = "正在倒计时";
if (this.state.isOver) {
status = "倒计时完成";
}
return (
<div>
<Tick
onClick={this.handleClick}
onOver={this.handleClick}
number={10} />
<h2>
{status}
</h2>
</div>
)
}
}
六、深入认识setState
setState,它对状态的改变,可能是异步的
如果改变状态的代码处于某个HTML元素的事件中,则其是异步的,否则是同步
如果遇到某个事件中,需要同步调用多次,需要使用函数的方式得到最新状态
最佳实践:
- 把所有的setState当作是异步的
- 永远不要信任setState调用之后的状态
- 如果要使用改变之后的状态,需要使用回调函数(setState的第二个参数)
- 如果新的状态要根据之前的状态进行运算,使用函数的方式改变状态(setState的第一个函数)
React会对异步的setState进行优化,将多次setState进行合并(将多次状态改变完成后,再统一对state进行改变,然后触发render)