setState()
let {count} = this.state;
// react的 setState 是异步执行的 !!!
// 对象式的 setState
// 第二个参数是回调函数、在setState() 函数和render()函数执行之后被调用
// 也就是说在这个回调函数中可以拿到更新后的状态
setState({count: count + 1}, () => {
});
// 函数式的 setState
// 对象式的 setState 是函数式 setState 的语法糖
setState((state, props) => {return {count: count + 1}})
lazy 组件懒加载
import React {lazy, Suspense} from "react";
import {Route} from "react-router-dom";
// 假设懒加载的组件为 Home 组件
// 传统的引入方式
import Home from "./Home/index";
// 懒加载的引入方式
const Home = lazy(() => import("./Home/index"));
// 开启组件懒加载
// fallback 路由组件加载过程中的展示组件 该组件不支持懒加载
<Suspense fallback={<h1>loading...</h1>}>
{/*注册路由*/}
<Route path="/home" component={Home}/>
</Suspense>
Hooks
# React Hooks 是什么?
- Hooks 是 React 16.8版本新增的特性
- 可以让你在函数式组件中中使用 state 以及其他的 React 特性
# 三个常用的 Hooks
- State Hook: React.useState()
- Effect Hook: React.useEffect()
- Ref Hook: React.useRef()
useState
export default Demo() {
// useState() 返回一个数组 count 为 初始状态 0
// setCount 为修改状态的函数 一个状态 对应一个修改状态的函数
/* setCount((newCount) => {return {count : newCount}}) */
const [count, setCount] = React.useState(0);
function add() {
// 第一种写法
setCount(count + 1);
// 第二种写法
setCount((count) => {return count + 1});
}
return (
<div>
<h2>当前的求和为 {count}</h2>
<button onClick={add}>点击+1</button>
</div>
)
}
useEffect
function Demo() {
const [count, setCount] = React.useState(0);
// useEffect() 在Demo方法第一次调用后执行
// useEffect() 的第二个参数为要监听的状态 如果为空数组 就相当于 didmount;
// 如果第二个参数为 [count] 即监听 count 状态的改变
// count 状态一改变、就执行回调函数
React.useEffect(() => {
setCount(count + 1);
return () => {
// 返回的函数相当于类式组件的 willunmount;
}
}, []);
}
useRef
function Demo() {
const myRef = React.useRef();
return (
<div>
{/*获得input 框的 value myRef.current.value*/}
<input type="text" ref={myRef}/>
</div>
)
}
Fragment
import React {Fragment} from "react";
function Demo() {
return (
<Fragment>
{/* Fragment 相当于 <> </> 但是 Fragment 可以有属性值 比如 key = {} */}
{/* 但是 <></> 标签不能有任何属性值 */}
</Fragment>
)
}
Content
# 组件间的通信方式
const MyContext = React.createContent();
const {Provider} = MyContext;
export default class A extends Component {
state = {username : "tom"}
render() {
return (
<div>
<Provider value={this.state.username}>
<B></B>
</Provider>
</div>
)
}
}
class B extends Component {
// 声明接受context
static contextType = MyContext;
render() {
return (
<div>
{this.context}
</div>
)
}
}
# 注意:在应用的开发中 我们一般不使用 context 而是使用 封装好的 React 插件
组件优化
# Component 的两个问题
- 只要执行 setState() 即使不改变状态数据 组件也会重新render()
- 只要当前组件重新 render() 就会自动更新 render 的子组件 *效率低*
# 效率高的做法
- 只有当组件的状态或属性发生变化时才重新 render()
# 原因
- component 的 shouldComponentUpdate() 总是返回 true
# 解决
## 方法一
- 重写 shouldComponentUpdate() 方法
- 比较新旧 state props 数据 如果有变化才返回 true 如果没有返回 false
## 方法二
- 继承 PureComponent
- PureComponent 重写了 shouldComponentUpdate()
- 只有 state 和 props 数据有变化 才返回 true
## 注意:
- 方法二只是进行 state 和 props 的地址比较 如果只是对象内部的数据变了 返回 false !!!
- 不要直接修改 state 数据 而是**产生**新数据 !!
## 实际项目开发中一般使用方法二进行组件优化
renderProps 插槽
export default class Parent extends Component {
render() {
<div>
<A render={(name) => <B name={name}/>}>
</div>
}
}
class A extends Component {
render() {
let {name} = this.state;
let {render} this.props;
return (
<>
{render(name)}
</>
}
}
}
错误边界
export default class Parent extends Component {
// 用于标识子组件是否产生错误
state = {hasError: ""}
// 当 Parent 的子组件出现错误时、会触发此函数的执行、并携带错误信息
static getDerivedStateFromError(error) {
return {hasError: error};
}
// 该生命周期钩子函数用于在组件出现错误时执行
// 向后台发送出现错误的消息和次数
componentDidCatch() {
}
render() {
return (
<>
{this.state.hasError ? "当前网络不稳定" : <A/>}
</>
)
}
}
未完待续…