生命周期
概念
1. 生命周期-概览
了解react类组件生命周期整体情况
大致步骤:
- 什么是生命周期
- React类组件的生命周期整体概览
- 了解生命周期的意义
具体内容:
- 什么是生命周期
- 一个事物从创建到最后消亡经历的整个过程
- React类组件的生命周期整体概览,组件从创建到消耗的过程
- 了解生命周期的意义
- 有助于理解组件的运行方式、完成更复杂的组件功能、分析组件错误原因
- 钩子函数为开发人员在不同阶段操作组件提供了时机
总结:
- 只有类组件才有生命周期,分为
挂载阶段更新阶段卸载阶段
阶段
2. 生命周期-挂载阶段
够说出组件的挂载阶段的钩子函数以及执行时机
大致步骤:
- 知道挂载阶段会执行那些函数,执行顺序
- 知道每个函数内一般可以做什么事
- 参考代码
具体内容:
- 知道挂载阶段会执行那些函数,执行顺序
- 知道每个函数内一般可以做什么事
| 钩子 函数 | 触发时机 | 作用 |
|---|---|---|
| constructor | 创建组件时,最先执行 | 1. 初始化state 2. 创建 Ref 3. 使用 bind 解决 this 指向问题等 |
| render | 每次组件渲染都会触发 | 渲染UI(注意: 不能调用setState() ) |
| componentDidMount | 组件挂载(完成DOM渲染)后 | 1. 发送网络请求 2.DOM操作 |
- 参考代码
import { Component } from 'react'
export default class App extends Component {
constructor () {
super()
console.log('1. constructor执行')
}
componentDidMount () {
console.log('3. componentDidMount执行')
}
render() {
console.log('2. render执行')
return <div>App组件</div>
}
}
总结:
- 组件挂载阶段,顺序执行
constructorrendercomponentDidMount三个函数
3. 生命周期-更新阶段
能够说出组件的更新阶段的钩子函数以及执行时机
大致步骤:
- 知道更新阶段会执行那些函数,执行顺序
- 知道何时触发更新阶段
- 知道触发的钩子函数里可以做些什么
- 参考代码
具体内容:
- 更新阶段会执行那些函数,执行顺序
- 何时触发更新阶段
- setState()
- forceUpdate() 强制组件更新
- 组件接收到新的props(实际上,只需要父组件更新,子组件就会重新渲染)
- 钩子函数里可以做什么
| 钩子函数 | 触发时机 | 作用 |
|---|---|---|
| render | 每次组件渲染都会触发 | 渲染UI(与 挂载阶段 是同一个render) |
| componentDidUpdate | 组件更新(完成DOM渲染)后 | DOM操作,可以获取到更新后的DOM内容,不要直接调用setState |
- 参考代码
import { Component } from 'react'
class Child extends Component {
render() {
return <h1>统计豆豆被打的次数:</h1>
}
}
export default class App extends Component {
state = {
count: 0
}
handleClick = () => {
this.setState({
count: this.state.count + 1
})
}
componentDidUpdate() {
console.log('2. componentDidUpdate执行')
}
render() {
console.log('1. render执行')
return (
<div>
<Child />
<button onClick={this.handleClick}>打豆豆</button>
</div>
)
}
}
总结:
- 组件更新会触发
componentDidUpdate钩子函数
4. 生命周期-卸载阶段
能够说出组件的销毁阶段的钩子函数以及执行时机
大致步骤:
- 什么时候触发卸载
- 卸载阶段执行那些钩子函数,一般做什么事情
- 参考代码
- 演示清理工作
具体内容:
- 什么时候触发卸载?
- 在组件被移除的时候(消失)触发卸载阶段
- 卸载阶段执行那些钩子函数,一般做什么事情
| 钩子函数 | 触发时机 | 作用 |
|---|---|---|
| componentWillUnmount | 组件卸载(从页面中消失) | 执行清理工作(比如:清理定时器等) |
- 参考代码
import { Component } from 'react'
class Child extends Component {
componentWillUnmount () {
console.log('componentWillUnmount执行')
}
render() {
return <h1>统计豆豆被打的次数:{this.props.count}</h1>
}
}
export default class App extends Component {
state = {
count: 0
}
handleClick = () => {
this.setState({
count: this.state.count + 1
})
}
render() {
return (
<div>
{ this.state.count < 5 && <Child count={this.state.count} />}
<button onClick={this.handleClick}>打豆豆</button>
</div>
)
}
}
总结:
- 组件卸载阶段执行
componentWillUnmount, 可以清理全局事件、定时器等。
使用
5. 生命周期 - 练习
能够实现youku评论列表案例的数据持久化
大致步骤:
- 在组件挂载的钩子函数中,从本地存储中读取 list 数据
- 将读取到的 list 数据,更新到状态中
- 在组件更新的钩子函数中,将最新的 list 数据存到本地存储中
核心代码:
componentDidUpdate() {
localStorage.setItem('comments', JSON.stringify(this.state.comments))
}
componentDidMount() {
const comments = JSON.parse(localStorage.getItem('comments') || '[]')
this.setState({ comments })
}
总结: 掌握生命周期的基本运用
todomvc案例优化
模拟接口
13. todomvc案例-模拟接口
使用json-server创建接口服务支持案例
大致步骤:
- 全局安装json-server
- 新建 db.json 文件
- 启动接口服务
- 接口地址列表
具体内容:
- 全局安装json-server
npm i json-server -g
- 新建 db.json 文件,内容如下
{
"todos": [
{"id":1,"name":"吃饭","done":true},
{"id":2,"name":"睡觉","done":false}
]
}
- 启动服务,在db.json文件目录下执行
json-server db.json
# 设置端口
# json-server db.json --port 5000
- 接口地址列表
GET /todos 获取列表
POST /todos 添加任务,参数 name 和 done
GET /todos/:id 获取任务,参数 id
DELETE /todos/:id 删除任务,参数 id
PUT /todos/:id 修改任务,参数 name 和 done , 完整更新
PATCH /todos/:id 修改任务,参数 name 或 done , 局部更新
功能
14. todomvc案例-静态结构
根据todomvc提供的资源搭建静态案例
TODOMVC官网:todomvc.com/
todo案例基础模版地址: todo-app-template
将基础模版加入到react脚手架中
react组件准备:
- 创建
index.css把css拷贝进去 - 创建
App.js组件,把html使用起来
import React, { Component } from 'react';
import './index.css'
export default class App extends Component {
render() {
return (
<section className="todoapp">
<header className="header">
<h1>todos</h1>
<input
className="new-todo"
placeholder="What needs to be done?"
autoFocus
/>
</header>
<section className="main">
<input id="toggle-all" className="toggle-all" type="checkbox" />
<label htmlFor="toggle-all">Mark all as complete</label>
<ul className="todo-list">
<li className="completed">
<div className="view">
<input className="toggle" type="checkbox" checked />
<label>Taste JavaScript</label>
<button className="destroy"></button>
</div>
<input className="edit" value="Create a TodoMVC template" />
</li>
<li>
<div className="view">
<input className="toggle" type="checkbox" />
<label>Buy a unicorn</label>
<button className="destroy"></button>
</div>
<input className="edit" value="Rule the web" />
</li>
</ul>
</section>
<footer className="footer">
<span className="todo-count">
<strong>0</strong> item left
</span>
<ul className="filters">
<li>
<a className="selected" href="#/">All</a>
</li>
<li>
<a href="#/active">Active</a>
</li>
<li>
<a href="#/completed">Completed</a>
</li>
</ul>
<button className="clear-completed">Clear completed</button>
</footer>
</section>
);
}
}
15. todomvc案例-列表渲染
完成组件的拆分和列表渲染
大致步骤:
- 拆分组件
- 安装axios,在App组件获取数据,传人Main渲染即可
具体代码:
- 拆分组件
App.jsx
import React, { Component } from "react";
import Footer from "./components/Footer";
import Header from "./components/Header";
import Main from "./components/Main";
export default class App extends Component {
render() {
return (
<section className="todoapp">
<Header />
<Main />
<Footer />
</section>
);
}
}
components/Header.jsx
import React, { Component } from "react";
export default class Header extends Component {
render() {
return (
<header className="header">
<h1>todos</h1>
<input
className="new-todo"
placeholder="What needs to be done?"
autoFocus
/>
</header>
);
}
}
components/Main.jsx
const Main = () => {
return (
<section className="main">
<input id="toggle-all" className="toggle-all" type="checkbox" />
<label htmlFor="toggle-all">Mark all as complete</label>
<ul className="todo-list">
<li className="completed">
<div className="view">
<input className="toggle" type="checkbox" checked />
<label>Taste JavaScript</label>
<button className="destroy"></button>
</div>
<input className="edit" value="Create a TodoMVC template" />
</li>
<li>
<div className="view">
<input className="toggle" type="checkbox" />
<label>Buy a unicorn</label>
<button className="destroy"></button>
</div>
<input className="edit" value="Rule the web" />
</li>
</ul>
</section>
);
};
export default Main;
components/Footer.jsx
const Footer = () => {
return (
<footer className="footer">
<span className="todo-count">
<strong>0</strong> item left
</span>
<ul className="filters">
<li>
<a className="selected" href="#/">
All
</a>
</li>
<li>
<a href="#/active">Active</a>
</li>
<li>
<a href="#/completed">Completed</a>
</li>
</ul>
<button className="clear-completed">Clear completed</button>
</footer>
);
};
export default Footer;
- 安装axios,在App组件获取数据,传人Main渲染即可
App.jsx
import React, { Component } from "react";
import Footer from "./components/Footer";
import Header from "./components/Header";
import Main from "./components/Main";
import axios from "axios";
export default class App extends Component {
state = {
list: [],
};
async componentDidMount() {
const res = await axios.get("http://localhost:5000/todos");
this.setState({ list: res.data });
}
render() {
return (
<section className="todoapp">
<Header />
<Main list={this.state.list} />
<Footer />
</section>
);
}
}
components/Main.jsx
import PropTypes from 'prop-types'
const Main = (props) => {
return (
<section className="main">
<input id="toggle-all" className="toggle-all" type="checkbox" />
<label htmlFor="toggle-all">Mark all as complete</label>
<ul className="todo-list">
{props.list.map((item) => (
<li key={item.id} className={item.done ? "completed" : ""}>
<div className="view">
<input className="toggle" type="checkbox" checked={item.done} onChange={()=>{}} />
<label>{item.name}</label>
<button className="destroy"></button>
</div>
<input className="edit"/>
</li>
))}
</ul>
</section>
);
};
Main.propTypes = {
list: PropTypes.array
}
export default Main;
16. todomvc案例-添加任务
完成添加任务功能
大致步骤:
- Header组件
- 绑定输入内容数据
- enter后拿着内容,发送添加请求
- 清空输入内容
- 更新列表
- App组件
- 提供更新列表函数,传递给Header组件使用
落地代码:
App组件
componentDidMount() {
this.getTodoList()
}
getTodoList = async () => {
const res = await axios.get("http://localhost:5000/todos");
this.setState({ list: res.data });
}
render() {
return (
<section className="todoapp">
<Header getTodoList={this.getTodoList} />
<Main list={this.state.list} />
<Footer />
</section>
);
}
Header组件
import React, { Component } from "react";
import axios from "axios";
import PropTypes from 'prop-types'
export default class Header extends Component {
static propTypes = {
getTodoList: PropTypes.func.isRequired
}
state = {
todoName: "",
};
onChange = (e) => {
this.setState({
todoName: e.target.value,
});
};
add = async (e) => {
if (e.keyCode === 13) {
const name = this.state.todoName.trim();
if (name) {
await axios.post("http://localhost:5000/todos", { name, done: false });
this.setState({ todoName: "" });
this.props.getTodoList();
}
}
};
render() {
return (
<header className="header">
<h1>todos</h1>
<input
className="new-todo"
placeholder="What needs to be done?"
autoFocus
value={this.state.todoName}
onChange={this.onChange}
onKeyUp={this.add}
/>
</header>
);
}
}
17. todomvc案例-修改状态&删除任务
完成修改状态功能&删除任务
大致步骤:
- Main组件
- 绑定checkbox的onChang事件,触发后发修改请求
- 绑定button的点击事件,触发后发删除请求
- 成功后更新列表
- App组件
- 传入更新列表函数
落地代码:Main组件
import PropTypes from "prop-types";
+import axios from "axios";
const Main = (props) => {
+ const updateDone = async (id, done) => {
+ await axios.patch(`http://localhost:5000/todos/${id}`, { done });
+ props.getTodoList()
+ };
+ const del = async (id) => {
+ await axios.delete(`http://localhost:5000/todos/${id}`);
+ props.getTodoList()
+ }
return (
<section className="main">
<input id="toggle-all" className="toggle-all" type="checkbox" />
<label htmlFor="toggle-all">Mark all as complete</label>
<ul className="todo-list">
{props.list.map((item) => (
<li key={item.id} className={item.done ? "completed" : ""}>
<div className="view">
<input
className="toggle"
type="checkbox"
checked={item.done}
+ onChange={() => updateDone(item.id, !item.done)}
/>
<label>{item.name}</label>
+ <button className="destroy" onClick={()=>del(item.id)}></button>
</div>
<input className="edit" />
</li>
))}
</ul>
</section>
);
};
Main.propTypes = {
list: PropTypes.array.isRequired,
+ getTodoList: PropTypes.func.isRequired,
};
export default Main;
App组件
<section className="todoapp">
<Header getTodoList={this.getTodoList} />
+ <Main list={this.state.list} getTodoList={this.getTodoList} />
<Footer />
</section>