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更新之后执行```javascriptimport 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)````javascriptimport 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 组件之间共享状态- 作用- 带着子组件去流浪- 注意事项- 上层数据发生改变,肯定会触发重现渲染```javascriptimport 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```javascriptimport 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;
```javascriptimport React from "react";import useLoadData from "../utils/useLoadDate";import useLocalReducer from "../utils/useLocalReducer";function StateFunction() {const [state, dispatch] = useLocalReducer();const [num, steNum] = useLoadData();return (<divonClick={() => {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() // 先执行一次 ```
