React新版本特性解读
- render支持返回数组和字符串
- 错误边界
- 提升SSR渲染速度,支持流式渲染
- 减少文件体积
生命周期函数更新
hooks之间的状态是独立的,有自己独立的上下文,不会出现混淆状态的情况
- 让函数组件有了状态管理
- 解决了组件树不直观、类组件难维护、逻辑不易复用的问题
由于函数每次渲染都会执行,所以React中多了一个状态控制,传入第二个参数,这样就可以避免函数重复执行的副作用
应用场景
利用hooks取代生命周期函数
- 让函数组件加上状态
- 处理发送请求
- 存取数据
-
定时器⏲清理
简单分析:
首先
useEffect
方法,是react新增的,它是componentDidMount
,componentDidUpdate
、componentWillUnmount
三个生命周期的合集,- 也就是之前的写法,上面三生命周期里会执行到的操作,useEffect都会去做;
useEffect
方法里return 一个方法,它是可以在组件卸载时执行的,- 清除定时器它有自己的方式,
const intervalRef = useRef()
;指定赋值后能同步更新,之前的timer手动执行没有拿到timer所以没有清除掉;
参考链接:https://blog.csdn.net/weixin_43254766/article/details/84842106
hooks API
useState
- 作用
- 函数组件添加状态
- 注意事项
- 初始化以及更新state
- 用来声明状态变量 ```javascript import React, { useState } from “react”;
function StateFunction() { // 使用useState来创建状态 // 1.引入 // 2.接收一个参数作为初始值 // 3.返回一个数组,第一个值为状态,第二个值为改变状态的函数 const [name, setName] = useState(“函数”); return (
export default StateFunction;
<a name="Q8rCi"></a>
#### useEffect 副作用hooks
- 作用
- 给没有生命周期的组件,添加结束渲染的信号
- 注意事项
- 在render之后执行
<a name="78xOD"></a>
#### useLayoutEffect-监测DOM
- 作用
- DOM更新完成后执行某个操作
- 相当于类组件里的componentWillmount
- 注意事项
- 有DOM操作的副作用hooks
- 在DOM更新之后执行
```javascript
import React, { useState, useEffect, useLayoutEffect } from "react";
function StateFunction() {
// 相似的用法
// 接收一个函数作为参数
// 接收第二个参数:依赖列表,只有依赖更新时,才会执行函数
// 返回一个函数,先执行返回函数,再执行参数函数
// 不同点
// useEffect 执行时机在render之后
// useLayoutEffect 执行时机在dom更新之后
const [Num, setNum] = useState(1);
useEffect(() => {
console.log("useEffect");
document.body.addEventListener("a", () => {});
return () => {
document.body.removeEventListener("a", () => {});
};
}, [Num]);
useLayoutEffect(() => {
console.log("useLayoutEffect");
document.body.addEventListener("a", () => {});
return () => {
document.body.removeEventListener("a", () => {});
};
});
return (
<div onClick={() => setNum((Num) => Num + 1)}>这是一个函数组件 - {Num}</div>
);
}
export default StateFunction;
useLayoutEffect会先打印,useEffect后打印。**useLayoutEffect模拟的是componentWillmount,useEffect模拟的时候**componentDidmount。
useMemo
- 作用
- 让组件中的函数跟随状态更新
- 注意事项
- 优化函数组件中的功能函数 ```javascript import React, { useState, useEffect, useLayoutEffect, useMemo } from “react”;
function StateFunction() { const [Num, setNum] = useState(1); const [age, setAge] = useState(18);
// const getDoubleNum = () => { // console.log(“获取双倍的num”); // return 2 * Num; // };
// useMemo使用方法 // 1.接收一个函数作为参数 // 2.第二个参数为依赖列表,useEffect,useLayoutEffect进行对比 // 3.返回的是一个值,不是函数 const getDoubleNum = useMemo(() => { console.log(“获取双倍的num”); return 2 * Num; }, [Num]);
return (
export default StateFunction;
<a name="t4hwX"></a>
#### useCallback
- 作用
- 跟随状态更新执行
- 注意事项
- 只有依赖项改变的时候才会执行
- `useMemo(()=>fn, deps)` 相当于 `useCallback(fn, deps)`
```javascript
import React, { useState, useCallback, Children, useEffect } from "react";
function StateFunction() {
const [Num, setNum] = useState(1);
const [age, setAge] = useState(18);
// const getDoubleNum = () => {
// console.log("获取双倍的num");
// return 2 * Num;
// };
// 在使用方法上,useCallback与useMemo相同
// 不同点
// useMemo返回的是一个值,useCallback返回的是一个函数
// useMemo缓存的是一个值,useCallback缓存的是一个函数
const getDoubleNum = useCallback(() => {
console.log("获取双倍的num");
return 2 * Num;
}, [Num]); // 依赖是[], 缓存的 函数不变,子组件不会更新。 依赖的是[Num],缓存的函数每次都会更新,子组件也会更新
return (
<div onClick={() => setAge((age) => age + 1)}>
Num的值为 - {getDoubleNum()}
age的值为 - {age}
<Child callback={getDoubleNum}></Child>
</div>
);
}
// 子组件
function Child(props) {
useEffect(() => {
console.log("callback更新了");
}, [props.callback]);
return <div>child</div>;
}
export default StateFunction;
useRef 长久保存数据
- 作用
- 长久保存数据
- 注意事项
- 返回一个子元素的索引,此索引在整个生命周期中保持不变
- 对象发生改变,不通知。属性变更不会触发重新渲染(重新赋值ref.current 不会触发重新渲染) ```javascript import React, { useState, useRef, useEffect } from “react”;
function StateFunction() { const [Num, setNum] = useState(1);
const ref = useRef(); useEffect(() => { ref.current = setInterval(() => { setNum((Num) => Num + 1); }, 400); }, []);
useEffect(() => { if (Num > 10) { console.log(“超过10了”, ref.current); clearInterval(ref.current); } }, [Num]);
return
export default StateFunction;
<a name="IlBhg"></a>
#### useContext 组件之间共享状态
- 作用
- 带着子组件去流浪
- 注意事项
- 上层数据发生改变,肯定会触发重现渲染
```javascript
import React, { useState, useContext, createContext } from "react";
// 1. 引入useContext, createContext
// 2. 通过createContext创建一个context句柄
// 3. Context.Provider来确定数据共享范围
// 4. 通过value来分发内容
// 5. 在子组件中,通过useContext(context句柄)来获取数据
const Context = createContext(null);
function StateFunction() {
const [Num, setNum] = useState(1);
return (
<div onClick={() => setNum((Num) => Num + 1)}>
Num的值为 - {Num}
<Context.Provider value={Num}>
<Item1 />
<Item2 />
</Context.Provider>
</div>
);
}
function Item1() {
const num = useContext(Context);
return <div>子组件{num}</div>;
}
function Item2() {
const num = useContext(Context);
return <div>子组件{num}</div>;
}
export default StateFunction;
useReducer 复杂逻辑简单化
- 作用
- 去其他地方借资源
- 注意事项
- 函数组件的redux操作 ```javascript import React, { useState, useReducer } from “react”;
// redux必须的内容 // store reducer
// useReducer使用方法 // 1. 需要创建数据仓库store和仓库管理者reducer // 2. 通过useReducer(reducer, store)来获取state和dispatch const store = { num: 10, };
const reducer = (state, action) => { switch (action.type) { case “changeNum”: return { …state, num: action.num, }; default: return { …state, }; } }; function StateFunction() { const [state, dispatch] = useReducer(reducer, store);
return (
export default StateFunction;
<a name="HnuGC"></a>
#### 自定义Hooks
- 作用
- 自定义Hooks以支持特殊场景
- 自定义Hooks注意事项
- 引入react和自己需要的hook
- 创建自己的hook函数
- 返回一个数组,**数组中第一个内容是数据,第一个是修改数据的函数**
- 将自己定义的hook函数暴露出去
- 在自己的业务组件中引入并使用
- **实现模拟的数据接口请求功能**
- useLoadDate.js
```javascript
import React, { useState, useEffect } from "react";
// 如何实现模拟的数据接口请求功能
function useLoadData() {
const [num, setNum] = useState(1);
useEffect(() => {
setTimeout(() => {
setNum(2);
}, 1000);
}, []);
return [num, setNum];
}
export default useLoadData;
import React from "react";
import useLoadData from "../utils/useLoadDate";
function StateFunction() {
const [num, steNum] = useLoadData();
return <div onClick={() => {}}>Num的值为 - {num}</div>;
}
export default StateFunction;
- 实现本地自定义的reducer
- useLocalReducer.js ```javascript import React, { useReducer } from “react”;
// 数据仓库 const store = { age: “111”, };
// 管理者 const reducer = (state, action) => { switch (action.type) { case “age”: return { …state, age: action.age, }; default: return { …state, }; } };
function useLocalReducer() { const [state, dispatch] = useReducer(reducer, store);
return [state, dispatch]; }
export default useLocalReducer;
```javascript
import React from "react";
import useLoadData from "../utils/useLoadDate";
import useLocalReducer from "../utils/useLocalReducer";
function StateFunction() {
const [state, dispatch] = useLocalReducer();
const [num, steNum] = useLoadData();
return (
<div
onClick={() => {
dispatch({
type: "age",
age: "222",
});
}}
>
Num的值为 - {num} --{state.age}
</div>
);
}
export default StateFunction;
使用hooks实现购物车功能
- 购物车功能
- 添加商品
- 显示商品
- 删除
- 全选
- 自定义hooks-useLocalContext ```javascript import React from ‘react’
// 引用单例模式,将context做唯一处理 const LocalContext = () => { // 闭包的方式 let context return () => { if(!context){ context = React.createContext(null) } return context } } export default LocalContext() // 先执行一次 ```