React 收集表单数据和 组件生命周期
- 一、收集表单数据
- 1、例子
- 1.1 需求:定义一个包含表单的组件,输入用户名密码后,点击登录提示输入信息
- 2、理解:包含表单的组件分类
- 2.1 受控组件
- 2.2 非受控组件
- 二、高阶函数\_函数柯里化
- 1、复习--对象相关的知识
- 2、高阶函数
- 3、函数柯里化
- 4、不用柯里化的写法
- 三、组件的生命周期
- 1、例子--引出生命周期
- 2、理解
- 3、生命周期(旧)
- 3.1 挂载时(初始化)的流程
- 3.2 更新时的流程
- 3.2.1 流程线路 2(setState 流程)
- 3.2.2 流程线路 3 (forceUpdate 流程)
- 3.2.3 流程线路 1 (父组件 render 流程)
- 3.3 总结生命周期(旧)
- 4、对比新旧生命周期
- 4.1 重要的钩子
- 4.2 即将废弃的钩子
- 4.3 getSnapshotBeforeUpdate的使用场景
- 4.3 总结新的生命周期(常用的 render、ComponentDidMount、componentWillUnmount 是没有更改的)
一、收集表单数据
1、例子
1.1 需求:定义一个包含表单的组件,输入用户名密码后,点击登录提示输入信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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>
<!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<!-- 此处一定要写babel -->
<script type="text/babel">
// 1、创建组件
class Login extends React.Component {
render() {
return (
<form action="xxx" onSubmit={this.submit}>
用户名:
<input
type="text"
ref={(c) => {
this.username = c
}}
placeholder="用户名"
name="username"
/>
<br />
密码:
<input
type="password"
ref={(c) => {
this.password = c
}}
placeholder="密码"
name="password"
/>
<button>登录</button>
</form>
)
}
submit = (e) => {
e.preventDefault()
let { password, username } = this
console.log(password.value, username.value)
}
}
// 2、渲染组件到页面
// ReactDOM.render(组件,容器)
ReactDOM.render(<Login />, document.getElementById('test'))
</script>
</body>
</html>
2、理解:包含表单的组件分类
2.1 受控组件
页面中所有的输入类的节点,随着输入将数据维护到状态中,使用的时候直接从状态中取,就是受控组件
受控组件的优势在于 可以减少 ref 的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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>
<!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<!-- 此处一定要写babel -->
<script type="text/babel">
// 1、创建组件
class Login extends React.Component {
// 初始化状态
state = {
username: '',
password: '',
}
render() {
return (
<form action="xxx" onSubmit={this.submit}>
用户名:
<input
type="text"
onChange={this.saveUsername}
placeholder="用户名"
name="username"
/>
<br />
密码:
<input
type="password"
onChange={this.savePassword}
placeholder="密码"
name="password"
/>
<button>登录</button>
</form>
)
}
// 保存用户名到状态中
saveUsername = (event) => {
this.setState({ username: event.target.value })
}
// 保存密码到状态中
savePassword = (event) => {
this.setState({ password: event.target.value })
}
// 表单提交回调
submit = (e) => {
e.preventDefault()
let { password, username } = this.state
console.log(password, username)
}
}
// 2、渲染组件到页面
// ReactDOM.render(组件,容器)
ReactDOM.render(<Login />, document.getElementById('test'))
</script>
</body>
</html>
2.2 非受控组件
页面中所有的输入类的节点,现用现取就是 非受控组件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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>
<!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<!-- 此处一定要写babel -->
<script type="text/babel">
// 1、创建组件
class Login extends React.Component {
render() {
return (
<form action="xxx" onSubmit={this.submit}>
用户名:
<input
type="text"
ref={(c) => {
this.username = c
}}
placeholder="用户名"
name="username"
/>
<br />
密码:
<input
type="password"
ref={(c) => {
this.password = c
}}
placeholder="密码"
name="password"
/>
<button>登录</button>
</form>
)
}
submit = (e) => {
e.preventDefault()
let { password, username } = this
console.log(password.value, username.value)
}
}
// 2、渲染组件到页面
// ReactDOM.render(组件,容器)
ReactDOM.render(<Login />, document.getElementById('test'))
</script>
</body>
</html>
二、高阶函数_函数柯里化
1、复习–对象相关的知识
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script type="text/javascript">
let a = 'name'
let obj = {} // {name: 'Tom'}
obj[a] = 'Tom'
console.log(obj)
</script>
</body>
</html>
2、高阶函数
如果一个函数符合下面 2 个规范中任何一个,那么该函数就是高阶函数
1)若 A 函数,接收的参数是一个函数,那么 A 就可以称为高阶函数
2)若 A 函数,调用的返回值依然是一个函数,那么 A 就可以称之为高阶函数
常见的高阶函数: arr.map()、arr.filter()、Promise、arr.find()、arr.reduce()、setTimout 等等
下面代码中的 saveFormData 函数就是一个高阶函数,符合了条件 2(返回值是一个函数)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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>
<!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<!-- 此处一定要写babel -->
<script type="text/babel">
// 1、创建组件
class Login extends React.Component {
// 初始化状态
state = {
username: '',
password: '',
}
render() {
return (
<form action="xxx" onSubmit={this.submit}>
用户名:
<input
type="text"
onChange={this.saveFormData('username')}
placeholder="用户名"
name="username"
/>
<br />
密码:
<input
type="password"
onChange={this.saveFormData('password')}
placeholder="密码"
name="password"
/>
<button>登录</button>
</form>
)
}
// 保存表单数据到状态中
saveFormData = (dataType) => {
// 把此函数交给 react 处理,react 可以传入一个 event
return (event) => {
console.log(dataType, event.target.value, this.state)
this.setState({ [dataType]: event.target.value })
}
// this.setState({ type: event.target.value })
}
// 表单提交回调
submit = (e) => {
e.preventDefault()
let { password, username } = this.state
console.log(password, username)
}
}
// 2、渲染组件到页面
// ReactDOM.render(组件,容器)
ReactDOM.render(<Login />, document.getElementById('test'))
</script>
</body>
</html>
3、函数柯里化
通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式
上一段代码中的 saveFormData 函数 就是一个函数柯里化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>演示柯里化</title>
</head>
<body>
<script type="text/javascript">
function sum(a) {
return (b) => {
return (c) => {
return a + b + c
}
}
}
console.log(sum(1)(12)(3))
</script>
</body>
</html>
4、不用柯里化的写法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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>
<!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<!-- 此处一定要写babel -->
<script type="text/babel">
// 1、创建组件
class Login extends React.Component {
// 初始化状态
state = {
username: '',
password: '',
}
render() {
return (
<form action="xxx" onSubmit={this.submit}>
用户名:
<input
type="text"
onChange={(event) => {
this.saveFormData('username', event)
}}
placeholder="用户名"
name="username"
/>
<br />
密码:
<input
type="password"
onChange={(event) => {
this.saveFormData('password', event)
}}
placeholder="密码"
name="password"
/>
<button>登录</button>
</form>
)
}
// 保存表单数据到状态中
saveFormData = (dataType, event) => {
this.setState({ [dataType]: event.target.value })
}
// 表单提交回调
submit = (e) => {
e.preventDefault()
let { password, username } = this.state
console.log(password, username)
}
}
// 2、渲染组件到页面
// ReactDOM.render(组件,容器)
ReactDOM.render(<Login />, document.getElementById('test'))
</script>
</body>
</html>
三、组件的生命周期
1、例子–引出生命周期
需求:自定义组件实现以下功能
1)让指定的文本做显示/隐藏 的渐变动画
2)从完全可见,到彻底消失,耗时 2s
3)点击 按钮 从界面卸载组件
挂载 mount
卸载 unMount
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<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>
<!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<!-- 此处一定要写babel -->
<script type="text/babel">
// 1、创建组件
// 生命周期回调函数《==》生命周期钩子函数《==》生命周期函数《==》生命周期钩子
class Life extends React.Component {
// 初始化状态
state = {
opacity: 1,
}
// render 调用的时机: 初始化渲染、状态更新之后
render() {
console.log('render')
return (
<div>
<h2 style={{ opacity: this.state.opacity }}>
React 学不会,咋可能啊
</h2>
<button onClick={this.deadHandle}>直接噶</button>
</div>
)
}
// componentDidMount 组件挂载完毕时调用
componentDidMount() {
console.log('componentDidMount')
this.timer = setInterval(() => {
let { opacity } = this.state
opacity -= 0.1
if (opacity <= 0) {
opacity = 1
}
// console.log(opacity)
this.setState({ opacity })
}, 200)
}
// 组件将要卸载的时候调用
componentWillUnmount() {
// 清除定时器
clearInterval(this.timer)
}
deadHandle = () => {
// // 清除定时器
// clearInterval(this.timer)
// 卸载组件
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
console.log('按钮点击,将组件直接卸载')
}
}
// 2、渲染组件到页面
// ReactDOM.render(组件,容器)
ReactDOM.render(<Life />, document.getElementById('test'))
</script>
</body>
</html>
2、理解
1)组件对象从创建到死亡它会经历特定阶段
2)React 组件对象包含一系列钩子函数(生命周期回调函数),在特定的时刻调用
3)我们在定义组件时候,在特定的生命周期回调函数中做特定的工作
3、生命周期(旧)
react v16.8.0
3.1 挂载时(初始化)的流程
执行顺序:
Count—constructor
Count—componentWillMount
Count—render
Count—componentDidMount
卸载组件按钮点击后执行:
Count—componentWillUnmount
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</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>
<!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<!-- 此处一定要写babel -->
<script type="text/babel">
class Count extends React.Component {
constructor(props) {
console.log('Count---constructor')
super(props)
this.state = {
num: 0,
}
}
addHandle = () => {
let { num } = this.state
this.setState({ num: num + 1 })
}
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
// 组件将要挂载的钩子
componentWillMount() {
console.log('Count---componentWillMount')
}
// 组件挂载完毕的钩子
componentDidMount() {
console.log('Count---componentDidMount')
}
// 组件卸载时的钩子
componentWillUnmount() {
console.log('Count---componentWillUnmount')
}
render() {
console.log('Count---render')
let { num } = this.state
return (
<div>
<h1>当前求和为 {num}</h1>
<button onClick={this.addHandle}>点我+1</button>
<button onClick={this.death}>卸载组件</button>
</div>
)
}
}
ReactDOM.render(<Count />, document.getElementById('test'))
</script>
</body>
</html>
3.2 更新时的流程
3.2.1 流程线路 2(setState 流程)
正常更新:修改状态中的数据 组件能够更新
执行顺序
Count—shouldComponentUpdate
Count—componentWillUpdate
Count—render
Count—componentDidUpdate
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</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>
<!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<!-- 此处一定要写babel -->
<script type="text/babel">
class Count extends React.Component {
constructor(props) {
console.log('Count---constructor')
super(props)
this.state = {
num: 0,
}
}
addHandle = () => {
let { num } = this.state
this.setState({ num: num + 1 })
}
death = () => {
ReactDOM.unmountComponentAtNode(document.getElementById('test'))
}
// 组件将要挂载的钩子
componentWillMount() {
console.log('Count---componentWillMount')
}
// 组件挂载完毕的钩子
componentDidMount() {
console.log('Count---componentDidMount')
}
// 组件卸载时的钩子
componentWillUnmount() {
console.log('Count---componentWillUnmount')
}
// 控制组件更新的“阀门”, 需要写一个返回值(类型为 boolean),返回false就不再更新
shouldComponentUpdate() {
console.log('Count---shouldComponentUpdate')
return true
}
// 组件将要更新的钩子
componentWillUpdate() {
console.log('Count---componentWillUpdate')
}
// 组件更新完毕的钩子
componentDidUpdate() {
console.log('Count---componentDidUpdate')
}
render() {
console.log('Count---render')
let { num } = this.state
return (
<div>
<h1>当前求和为 {num}</h1>
<button onClick={this.addHandle}>点我+1</button>
<button onClick={this.death}>卸载组件</button>
</div>
)
}
}
ReactDOM.render(<Count />, document.getElementById('test'))
</script>
</body>
</html>
3.2.2 流程线路 3 (forceUpdate 流程)
强制更新: 不修改状态中的数据但是想要更新页面就会用到。 阀门关闭也不会影响
执行顺序:
Count—componentWillUpdate
Count—render
Count—componentDidUpdate
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</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>
<!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<!-- 此处一定要写babel -->
<script type="text/babel">
class Count extends React.Component {
constructor(props) {
console.log('Count---constructor')
super(props)
this.state = {
num: 0,
}
}
addHandle = () => {
let { num } = this.state
this.setState({ num: num + 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')
}
// 控制组件更新的“阀门”, 需要写一个返回值(类型为 boolean),返回false就不再更新
shouldComponentUpdate() {
console.log('Count---shouldComponentUpdate')
return true
}
// 组件将要更新的钩子
componentWillUpdate() {
console.log('Count---componentWillUpdate')
}
// 组件更新完毕的钩子
componentDidUpdate() {
console.log('Count---componentDidUpdate')
}
render() {
console.log('Count---render')
let { num } = this.state
return (
<div>
<h1>当前求和为 {num}</h1>
<button onClick={this.addHandle}>点我+1</button>
<button onClick={this.death}>卸载组件</button>
<button onClick={this.force}>
不更改任何状态的数据,强制更新一下
</button>
</div>
)
}
}
ReactDOM.render(<Count />, document.getElementById('test'))
</script>
</body>
</html>
3.2.3 流程线路 1 (父组件 render 流程)
执行顺序:
Child—render
Child—componentWillReceiveProps {carName: ‘奥迪’}
Child—shouldComponentUpdate
Child—componentWillUpdate
Child—render
Child—componentDidUpdate
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</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>
<!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<!-- 此处一定要写babel -->
<script type="text/babel">
class Parent extends React.Component {
// 初始化状态
state = {
carName: '奔驰',
}
changeCar = () => {
this.setState({ carName: '奥迪' })
}
render() {
let { carName } = this.state
return (
<div>
Parent, 我是父组件
<button onClick={this.changeCar}>换车</button>
<Child carName={carName} />
</div>
)
}
}
class Child extends React.Component {
// 组件将要接收新的prps 的钩子第一次传的不算, 之后的就能够执行,还能够接收到props参数
componentWillReceiveProps(props) {
console.log('Child---componentWillReceiveProps', props)
}
// 控制组件更新的“阀门”, 需要写一个返回值(类型为 boolean),返回false就不再更新
shouldComponentUpdate() {
console.log('Child---shouldComponentUpdate')
return true
}
// 组件将要更新的钩子
componentWillUpdate() {
console.log('Child---componentWillUpdate')
}
// 组件更新完毕的钩子
componentDidUpdate() {
console.log('Child---componentDidUpdate')
}
render() {
console.log('Child---render')
return <div>Child, 我是子组件,接收到的车是{this.props.carName}</div>
}
}
ReactDOM.render(<Parent />, document.getElementById('test'))
</script>
</body>
</html>
3.3 总结生命周期(旧)
生命周期的三个阶段
**1、初始化阶段:**由 ReactDom.render() 触发—初次渲染
constructor()
componentWillMount()
render()
componentDidMount() ====》常用,一般再这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
**2、更新阶段:**由组件内部 this.setState() 或父组件重新 render 触发
shouldComponentUpdate()
componentWillUpdate()
render() =======>必须
componentDidUpdate()
**3、卸载组件:**由 ReactDOM.unmountComponentAtNode() 触发
componentWillUnmount() ====》常用,一般再这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息
4、对比新旧生命周期
新的生命周期即将不再维护componentWillMount、componentWillUpdate、
新增 getDerivedStateFromProps、getSnapshotBeforeUpdate,但是不是替代之前前面丢弃的钩子,这两个新的钩子基本不用
React v18.3.0
4.1 重要的钩子
render:初始化渲染或更新渲染调用
ComponentDidMount:开启监听,发送 ajax请求
componentWillUnmount:做一些收尾工作,如:清理定时器
4.2 即将废弃的钩子
omponentWillMount
componentWillUpdate
componentWillUnmount
4.3 getSnapshotBeforeUpdate的使用场景
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>生命周期(新)</title>
<style>
.list {
width: 200px;
height: 150px;
background-color: skyblue;
overflow-y: auto;
}
.news {
height: 30px;
}
</style>
</head>
<body>
<div id="test"></div>
<!-- 引入 react 核心库 -->
<script type="text/javascript" src="../js/v18.3.0/react.development.js"></script>
<!-- 引入 react-dom,用于支持 react 操作DOM -->
<script
type="text/javascript"
src="../js/v18.3.0/react-dom.development.js"
></script>
<!-- 引入babel, 用于将 jsx 转为 js -->
<script type="text/javascript" src="../js/v18.3.0/babel.min.js"></script>
<!-- 引入 prop-types,用于对组件标签属性进行限制, 存在 PropTypes -->
<script type="text/javascript" src="../js/v18.3.0/prop-types.js"></script>
<!-- 此处一定要写babel -->
<script type="text/babel">
class NewsList extends React.Component {
state = {
newArr:[]
}
componentDidMount(){
this.timer = setInterval(()=>{
const {newArr} = this.state
let news = '新闻'+(newArr.length+1)
this.setState({
newArr: [news, ...newArr]
})
},1000)
}
// 在更新之前获取快照
getSnapshotBeforeUpdate(){
console.log("getSnapshotBeforeUpdate", this.refs.list.scrollHeight)
return this.refs.list.scrollHeigh
}
componentDidUpdate(prePops, preState, height){
this.refs.list.scrollTop += this.refs.list.scrollHeight-height
}
render() {
console.log('Count---render')
return (
<div className="list" ref='list'>
{this.state.newArr.map((el,inx)=>{
return <div className="news" key={inx}>{el}</div>
})}
</div>
)
}
}
ReactDOM.render(<NewsList />, document.getElementById('test'))
</script>
</body>
</html>
4.3 总结新的生命周期(常用的 render、ComponentDidMount、componentWillUnmount 是没有更改的)
**1、初始化阶段:**由 ReactDom.render() 触发—初次渲染
constructor()
getDerivedStateFromProps()
render()
componentDidMount() ====》常用,一般再这个钩子中做一些初始化的事,例如:开启定时器、发送网络请求、订阅消息
**2、更新阶段:**由组件内部 this.setState() 或父组件重新 render 触发
getDerivedStateFromProps
shouldComponentUpdate()
render() =======>必须
getSnapshotBeforeUpdate()
componentDidUpdate()
**3、卸载组件:**由 ReactDOM.unmountComponentAtNode() 触发
componentWillUnmount() ====》常用,一般再这个钩子中做一些收尾的事,例如:关闭定时器、取消订阅消息