2.1 基本理解和使用
2.1.1 使用 React 开发者工具调试
2.1.2 效果
函数组件
<!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 MyComponent(){
console.log(this) //此处的this是undefined , 因为babel编译后开启了严格模式
return <h2> 我是用函数定义的组件(适用于【简单组件】的定义)</h2>
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/> ,document.getElementById('test'))
/*
// 执行了ReactDOM.render(<MyComponent/>) ....之后,发生了什么?
1. React解析组件标签,找到了MyComponent标签
2. 发现组件是使用函数定义定义的,随后调用该函数,将返回的虚拟DOM 转为真实的DOM,随后呈现在页面中。
*/
</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">
//1.创建类似组件
class MyComponent extends React.Component{
render() {
//render是放在哪里的, - MyComponent的原型对象上,供实例使用
//render中this是谁,—— MyComponent的实例对象 MyComponent组件实例对象
console.log("render中的this:",this)
return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
}
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/> ,document.getElementById('test'))
/* 执行了ReactDOM.render(<MyComponent/> ,document.getElementById('')) 之后,发生了什么
1. react解析组件标签,找到了MyComponent组件
2. 发现组件是使用类定义的,随后new出来的该类的实例,并通过该实例调用到原型上的render方法。
3.将render返回的虚拟DOM转为真实DOM ,随后呈现在页面上。*/
</script>
</body>
</html>
2.1.3 注意
- 组件名必须首字母大写
- 虚拟DOM元素只能有一个根元素
- 虚拟DOM元素必须有结束标签
2.1.4 渲染类组件标签的基本流程
- React 内部会创建组件实例对象
- 调用 render() 得到虚拟 DOM ,并解析为真实的DOM。
- 插入到指定的页面元素内部。
2.2. 组件三大核心属性 1: false
2.2.1 效果
需求: 定义一个展示天气信息的组件
- 默认展示天气炎热 或 凉爽
- 点击文字切换天气
第一种方式
<!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 次
constructor(props){
console.log('constuctor')
super(props)
//初始化状态
this.state = {isHot:false,wind: '微风'}
//解决changeWeather中this指向问题
this.changeWeather = this.changeWeather.bind(this)
}
//render调用几次, ----1+n次 1是初始化的那次,n是状态更新的次数
render(){
console.log("render")
//读取状态
const {isHot,wind} = this.state
return <h1 onClick={this.changeWeather}> 今天天气很{isHot?'炎热':'凉爽'},{wind}</h1>
}
//changeWeather 调用几次? 点几次调几次
changeWeather(){
//changeWeather放在哪里? ----Weather 的原型对象上, 供实例使用
//由于changeWeather是作为onClick的调用,所以不是通过实例调用的,是直接调用
//类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
console.log('changeWeather')
//获取原来的isHot的值
const isHot = this.state.isHot
//严重注意: 状态必须通过setState进行更新,且更新是一种合法,不是替换
this.setState({isHot:!isHot})
console.log(this)
//严重注意:状态(state)不可直接更改,下面这行就是直接更改!!!
this.state.isHot = !isHot//这是错误的写法
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather></Weather>,document.getElementById('test'))
</script>
</body>
</html>
第二种方式
<!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></Weather>,document.getElementById('test'))
</script>
</body>
</html>
2.2.2. 理解
- state 是组件对象最重要的属性,值是对象(可以包含多个 key - value 的组合)
- 组件被称为 “状态机”,通过更新组件的 state 来更新对应的页面显示(重新渲染组件)
2.2.3 强烈注意
- 组件中 render 方法中的 this 为组价实例对象。
- 组件自定义的方法中 this undefined ,如何解决?
a. 强制绑定 this , 通过函数对象的 bind()
b. 箭头函数
- 状态数据,不能直接修改 或 更新
2.3. 组件三大核心属性2: props
2.3.1 效果
需求: 自定义用来显示一个人信息的组件
- 姓名必须指定,且为字符串类型。
- 性别为字符串类型,如果性别没有指定,默认为男。
- 年龄为字符串类型,且为数字类型,默认值为18
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(){
console.log(this)
const {name,age,sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}</li>
</ul>
)
}
}
ReactDOM.render(<Person name="jerry" age={19} sex="男"></Person>,document.getElementById('test1'))
ReactDOM.render(<Person name="tom" age={19} sex="女"></Person>,document.getElementById('test2'))
const person = {name:'老刘',age: 19,sex:'女' }
// ReactDOM.render(<Person name={person.name} age={person.age} sex={person.sex}></Person>,document.getElementById('test1'))
ReactDOM.render(<Person {...person}></Person>,document.getElementById('test3'))
</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{
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>
)
}
}
//对标签属性进行类型、必要性的限制
Person.propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串
sex:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
speak:PropTypes.func,//限制speak为函数
}
//指定默认标签属性值
Person.defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
//渲染组件到页面
ReactDOM.render(<Person name={100} speak={speak}/>,document.getElementById('test1'))
ReactDOM.render(<Person name="tom" age={18} sex="女"/>,document.getElementById('test2'))
const p = {name:'老刘',age:18,sex:'女'}
// console.log('@',...p);
// ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3'))
ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))
function speak(){
console.log('我说话了');
}
</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 {
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>
函数组件使用 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">
//创建组件
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>
2.3.2 理解
- 每个组件对象都会有props(properties 的简写)属性
- 组件标签的所有属性都保存在props
2.3.3 作用
- 通过标签属性从组件外向组件内传递变化的数据。
- 注意: 组件内部不要修改 props 数据。
2.3.4 编码操作
内部读取某个属性值
this.props.name
对 props 中的属性值进行类型限制和必要性限制
第一种方式(React v15.5 开始已弃用)
Person.propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number
}
第二种方式 (新): 使用prop-types 库进限制(需要引入prop - types)
Person.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number.
}
- 扩展属性: 将对象的所有属性通过 props 传递
<Person {...person}/>
- 默认属性值
Person。defaultProps = {
age: 18,
sex: ‘男’
}
- 组件类的构造函数
constructor(props){ super(props) console.log(props)//打印所有属性 }
2.4. 组件三大核心属性3: refs 与 事件处理
2.4.1 效果
需求: 自定义组件,功能说明如下:
- 点击按钮,提示第一个输入框中的值。
- 当第2个输入框失去焦点时,提示这个输入框中的值。
字符串形式的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 {input} = this.refs
alert(input.value)
}
//展示右侧输入框的数据
showData2 = () =>{
const {input1} = this.refs
alert(input1.value)
}
render() {
return (
<div>
<input ref="input" type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}> 点我提示左侧的数据</button>
<input ref = "input1" 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>2_回调函数形式的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 {input} = this
alert(input.value)
}
//展示右侧输入框的数据
showData2 = () =>{
const {input1} = this
alert(input1.value)
}
render() {
return (
<div>
<input ref={c => this.input = c} type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}> 点我提示左侧的数据</button>
<input onBlur={this.showData2} ref={c => this.input1 = c} 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>2_回调函数形式的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 {input} = this
alert(input.value)
}
//展示右侧输入框的数据
showData2 = () =>{
const {input1} = this
alert(input1.value)
}
render() {
return (
<div>
<input ref={c => this.input = c} type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}> 点我提示左侧的数据</button>
<input onBlur={this.showData2} ref={c => this.input1 = c} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo a="1" b='2'/> , 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所标识的节点,该容器是“专人专用”的
*/
myRef = React.createRef()
myRef2 = React.createRef()
//展示左侧输入框的数据
showData = ()=>{
alert(this.myRef.current.value);
}
//展示右侧输入框的数据
showData2 = ()=>{
alert(this.myRef2.current.value);
}
render(){
return(
<div>
<input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/>
<button onClick={this.showData}>点我提示左侧的数据</button>
<input onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo a="1" b="2"/>,document.getElementById('test'))
</script>
</body>
</html>
2.4.2 理解
组件内的标签可以定义ref属性来标识自己
2.4.3 编码
字符串形式的 ref
<input ref="input1"/>
回调形式的 ref
<input ref = { (c) => {this.input1 = c}}
- createRef 创建 ref 容器
myRef = React.createRef()
<input ref={this.myRef} />
2.4.4. 事件处理
- 通过 onXxx 属性指定事件 处理函数(注意大小写)
- React 使用的是自定义 (合成)事件,而不是使用的原生DOM事件。
- React 中的事件是通过委托方式处理的(委托给组件最外层的元素)
- 通过 event.target 得到发生事件的DOM元素对象。
<!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)=>{
console.log(event.target);
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>
2.5 收集表单数据
2.5.1 效果
需求: 定义一个包含表单的组件
输入用户名密码后,点击登录提示输入信息
2.5.2 理解
包含表单的组件分类
- 受控组件
- 非受控组件
非受控组件
**
<!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 onSubmit={this.handleSubmit}>
用户名: <input ref={c => this.username = c} type="text" name="username"/>
密码: <input ref={c => this.password = c} type="password" name="password"/>
<button> 登录</button>
</form>
)
}
}
//渲染组件
ReactDOM.render(<Login/>,document.getElementById('test'))
</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:'' //密码
}
//保存用户名到状态中
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>
2.6. 组件的生命周期
2.6.1 效果
需求: 定义组件实现以下功能:
- 让指定的文本做显示 / 隐藏的渐变动画
- 从完全可见,到彻底消失,耗时2S。
- 点击 “不活了” 按钮从界面消失。
编码实现:
<!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>
2.6.2 理解
- 组件从创建到死亡它会经历一些特定的阶段。
- React 组件中包含一系列勾子函数(生命周期函数),会在特定的时刻调用。
- 我们在定义组件时,会在特定的生命周期回调函数中,做特定的工作。
2.6.3 生命周期流程图(旧)
初始化阶段: 由 ReactDOM.render() 触发 —- 初次渲染
- constructor
- componentWillMount()
- render()
- componentDidMount()
更新阶段: 由组件内部 this.setState()或 父组件重新 render 触发
- shouldComponentUpdate()
- componentWillUpdate()
- render()
- componentDidUpdate()
卸载组件: 由ReactDOM.unmountComponentAtNode() 触发
- componentWillUnMount()
2.6.4. 生命周期流程图(新)
生命周期的三个阶段(新)
- 初始化阶段 : 由 ReactDOM.render() 触发—-初次渲染
- constructor
- getDerivedStateFromProps
- render()
- componentDidMount()
- 更新阶段:由 组件内部 this.setState( ) 或 父组件重新 render 触发
- getDerivedStateFromProps
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate
- componentDidUpdate()
- 卸载组件: 由 ReactDOM.unmountComponentAtNode() 触发
- componentWillUNmount()
2.6.5. 重要的勾子
- render : 初始化渲染或更新渲染调用
- componentDidMount: 开启监听,发送 ajax 请求。
- compoentWillUnmount : 做一些收尾工作,如: 清理定时器
2.6.6 即将废弃的勾子
- componentWillMount
- componentWillReceivedProps
- componentWillUpdate
现在使用会出现警告,下一个大版本需要加上 UNSAFE_ 前缀才能使用,以后可能会被彻底废弃,不建议使用。
2.7 虚拟 DOM 与 DOM Diffing 算法
2.7.1 效果
需求: 验证虚拟 DOM Different 算法的存在
2.7.2 基本原理图
<!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>