wordpress应用,优化大师卸载不了,wordpress更新下固定链接,学生个人网站布局背景
class 组件如果业务复杂#xff0c;很难拆分和重构#xff0c;很难测试#xff1b;相同业务逻辑分散到各个方法中#xff0c;逻辑混乱逻辑复用像HOC、Render Props#xff0c;不易理解#xff0c;学习成本高React提倡函数式编程#xff0c;函数更易拆分#xff0…背景
class 组件如果业务复杂很难拆分和重构很难测试相同业务逻辑分散到各个方法中逻辑混乱逻辑复用像HOC、Render Props不易理解学习成本高React提倡函数式编程函数更易拆分更易测试但是函数组件太简单为了增强函数组件的功能媲美class组件 函数组件没有state和setState函数组件没有生命周期
React Hooks 使用规范
只能用于 React 函数组件和自定义Hook 中其他地方不可以只能用于顶层代码不能在循环、判断中使用Hookseslint 插件 eslint-plugin-react-hooks
基本使用
useState
可用于模拟class组件的state和setState
import React, { useState } from react;function ClickCounter() {// 数组的解构// useState 是最基本的一个 Hookconst [count, setCount] useState(0); // 传入一个初始值const [name, setName] useState(章三);// const arr useState(0);// const count arr[0];// const setCount arr[1];function clickHandler() {setCount(count 1);setName(name 2020);}return (divp你点击了 {count} 次 {name}/pbutton onClick{clickHandler}点击/button/div);
}export default ClickCounter;useEffect 模拟生命周期
默认函数组件没有生命周期函数组件是一个纯函数执行完即销毁自己无法实现生命周期使用 Effect hooks 可以把生命周期“钩”到函数组件中
useEffect 中返回函数 fn
useEffect 依赖[]组件销毁是执行fn等于 componentWillUnmountuseEffect 无依赖或依赖[ab]组件更新时执行 fn即下一次执行useEffect之前就会执行fn无论更新或卸载
import React, { useState, useEffect } from react;function LifeCycles() {const [count, setCount] useState(0);const [name, setName] useState(章三);// // 模拟 class 组件的 DidMount 和 DidUpdate// useEffect(() {// console.log(在此发送一个 ajax 请求);// });// // 模拟 class 组件的 DidMount// useEffect(() {// console.log(加载完了);// }, []) // 第二个参数是 [] 不依赖于任何 state;// // 模拟 class 组件的 DidUpdate// useEffect(() {// console.log(更新了);// }, [count, name]); // 第二个参数就是依赖的 state// 模拟 class 组件的 DidMountuseEffect(() {let timerId window.setInterval(() {console.log(Date.now());}, 1000);// 返回一个函数// 模拟 WillUnMountreturn () {window.clearInterval(timerId);};}, []);function clickHandler() {setCount(count 1);setName(name 2020);}return (divp你点击了 {count} 次 {name}/pbutton onClick{clickHandler}点击/button/div);
}export default LifeCycles;
模拟 componentWillUnMount 注意事项
import React from react;class FriendStatus extends React.Component {constructor(props) {super(props);this.state {status: false // 默认当前不在线};}render() {return (div好友 {this.props.friendId} 在线状态{this.state.status}/div);}componentDidMount() {console.log(开始监听 ${this.props.friendId} 的在线状态);}componentWillUnmount() {console.log(结束监听 ${this.props.friendId} 的在线状态);}// friendId 更新componentDidUpdate(prevProps) {console.log(结束监听 ${prevProps.friendId} 在线状态);console.log(开始监听 ${this.props.friendId} 在线状态);}
}export default FriendStatus;import React, { useState, useEffect } from react;function FriendStatus({ friendId }) {const [status, setStatus] useState(false);// DidMount 和 DidUpdateuseEffect(() {console.log(开始监听 ${friendId} 在线状态);// 【特别注意】// 此处并不完全等同于 componentWillUnMount// props 发生变化即更新也会执行结束监听// 准确的说返回的函数会在下一次 effect 执行之前被执行return () {console.log(结束监听 ${friendId} 在线状态);};});return (div好友 {friendId} 在线状态{status.toString()}/div);
}export default FriendStatus;
useRef
获取 dom 节点
import React, { useRef, useEffect } from react;function UseRef() {const btnRef useRef(null); // 初始值// const numRef useRef(0);// numRef.current;useEffect(() {console.log(btnRef.current); // DOM 节点}, []);return (divbutton ref{btnRef}click/button/div);
}export default UseRef;useContext
定义一个主题可隔层传递
import React, { useContext } from react;// 主题颜色
const themes {light: {foreground: #000,background: #eee},dark: {foreground: #fff,background: #222}
};// 创建 Context
const ThemeContext React.createContext(themes.light); // 初始值function ThemeButton() {const theme useContext(ThemeContext);return (button style{{ background: theme.background, color: theme.foreground }}hello world/button);
}function Toolbar() {return (divThemeButton/ThemeButton/div);
}function App() {return (ThemeContext.Provider value{themes.dark}Toolbar/Toolbar/ThemeContext.Provider);
}export default App;useReducer
useReducer 和 redux 的区别
useReducer 是useState的代替方案用于state 复杂变化useReducer 是单个组件状态管理组件通讯还需要propsredux 是全局的状态管理多组件共享数据
import React, { useReducer } from react;const initialState { count: 0 };const reducer (state, action) {switch (action.type) {case increment:return { count: state.count 1 };case decrement:return { count: state.count - 1 };default:return state;}
};function App() {// 很像 const [count, setCount] useState(0)const [state, dispatch] useReducer(reducer, initialState);return (divcount: {state.count}button onClick{() dispatch({ type: increment })}increment/buttonbutton onClick{() dispatch({ type: decrement })}decrement/button/div);
}export default App;useMemo
React 默认会更新所有子组件class 组件使用 SCU 和 PureComponent做优化Hooks 中使用useMemo但优化的原理是相同的
使用 useMemo做性能优化
useMemo 缓存值依赖不变useMemo会取上一次缓存的值一般用于避免复杂计算。
import React, { useState, memo, useMemo } from react;// 子组件
// function Child({ userInfo }) {
// console.log(Child render..., userInfo);// return (div
// pThis is Child {userInfo.name} {userInfo.age}/p
// /div);
// }// 类似 class PureComponent 对 props 进行浅层比较
const Child memo(({ userInfo }) {console.log(Child render..., userInfo);return (divpThis is Child {userInfo.name} {userInfo.age}/p/div);
});// 父组件
function App() {console.log(Parent render...);const [count, setCount] useState(0);const [name, setName] useState(章三);// const userInfo { name, age: 20 }// 用 useMemo 缓存数据有依赖const userInfo useMemo(() {return { name, age: 21 };}, [name]);return (divpcount is {count}button onClick{() setCount(count 1)}click/button/pChild userInfo{userInfo}/Child/div);
}export default App;useCallback
使用 useCallback做性能优化
useCallback 缓存函数依赖不变useCallback会取上一次缓存的函数一般用于父组件给子组件传递函数减少子组件的渲染次数。
import React, { useState, memo, useMemo, useCallback } from react;// 子组件memo 相当于 PureComponent
const Child memo(({ userInfo, onChange }) {console.log(Child render..., userInfo);return (divpThis is Child {userInfo.name} {userInfo.age}/pinput onChange{onChange}/input/div);
});// 父组件
function App() {console.log(Parent render...);const [count, setCount] useState(0);const [name, setName] useState(章三);// 用 useMemo 缓存数据const userInfo useMemo(() {return { name, age: 21 };}, [name]);// function onChange(e) {// console.log(e.target.value);// }// 用 useCallback 缓存函数const onChange useCallback(e {console.log(e.target.value);}, []);return (divpcount is {count}button onClick{() setCount(count 1)}click/button/pChild userInfo{userInfo} onChange{onChange}/Child/div);
}export default App;自定义 hooks
作用
封装通用的功能开发和使用第三方 Hooks自定义 Hook 带来了无限的扩展性解耦代码
使用
本质是一个函数以 use 开头内部正常使用 useState、useEffect 获取其他 Hooks自定义返回结果格式不限
import { useState, useEffect } from react;function useMousePosition() {const [x, setX] useState(0);const [y, setY] useState(0);useEffect(() {function mouseMoveHandler(event) {setX(event.clientX);setY(event.clientY);}// 绑定事件document.body.addEventListener(mousemove, mouseMoveHandler);// 解绑事件return () document.body.removeEventListener(mousemove, mouseMoveHandler);}, []);return [x, y];
}export default useMousePosition;import { useState, useEffect } from react;
import axios from axios;// 封装 axios 发送网络请求的自定义 Hook
function useAxios(url) {const [loading, setLoading] useState(false);const [data, setData] useState();const [error, setError] useState();useEffect(() {// 利用 axios 发送网络请求setLoading(true);axios.get(url) // 发送一个 get 请求.then(res setData(res)).catch(err setError(err)).finally(() setLoading(false));}, [url]);return [loading, data, error];
}export default useAxios;// 第三方 Hook
// https://nikgraf.github.io/react-hooks/
// https://github.com/umijs/hookshooks 注意事项
useState 初始化值只有第一次有效useEffect 内部不能修改 stateuseEffect 可能出现死循环
// 关于 useEffect 内部不能修改 state 的问题
import { useEffect, useState } from react;const HelloWorld () {const [count, setCount] useState(0);useEffect(() {const timer setInterval(() {setCount(pre pre 1);}, 1000);return () clearInterval(timer);}, []);return (p{count}/p);
}export default HelloWorld;为何 hooks 要依赖于调用顺序
import React, { useState, useEffect } from react;function Teach({ couseName }) {// 函数组件纯函数执行完即销毁// 所以无论组件初始化render还是组件更新re-render// 都会重新执行一次这个函数获取最新的组件// 这一点和 class 组件不一样// render: 初始化 state 的值 张三// re-render: 读取 state 的值 张三const [studentName, setStudentName] useState(张三);// if (couseName) {// const [studentName, setStudentName] useState(张三);// }// render: 初始化 state 的值 里斯// re-render: 读取 state 的值 里斯const [teacherName, setTeacherName] useState(里斯)// if (couseName) {// useEffect(() {// // 模拟学生签到// localStorage.setItem(name, studentName);// });// }// render: 添加 effect 函数// re-render: 替换 effect 函数内部的函数也会重新定义useEffect(() {// 模拟学生签到localStorage.setItem(name, studentName);});// render: 添加 effect 函数// re-render: 替换 effect 函数内部的函数也会重新定义useEffect(() {// 模拟开始上课console.log(${teacherName} 开始上课学生 ${studentName});});return (div课程{couseName}讲师{teacherName}学生{studentName}/div);
}export default Teach;FQA
为什么会有 React hooks
class 组件不易拆分、不易测试、业务代码分散在各个方法中函数组件更易拆分和测试但是函数组件没有state和生命周期所以需要使用hooks来增强函数组件的功能
React hooks 如何模拟生命周期
模拟componentDidMount - useEffect 依赖 []模拟componentDidUpdate - useEffect 无依赖或者依赖 [a,b]模拟componentWillUnMount - useEffect 依赖 []并返回一个函数
如何自定义hooks
以 use 开头定义一个函数内部正常使用 useState、useEffect 获取其他 Hooks自定义返回结果格式不限
为什么要使用 hooks?
完善函数组件的能力函数更适合React组件组件逻辑复用hooks表现更好
hooks 组件逻辑复用的好处
HOC 组件层级嵌套过多不易渲染不易调试 HOC 会劫持props必须严格规范容易出现疏漏Render Props 学习成本高不易理解;只能传递纯函数而默认情况下纯函数功能有限hooks 做组件逻辑复用完全符合hooks原有原则没有其他要求易理解记忆变量作用域明确不会产生组件嵌套
React hooks 容易遇到哪些坑
useState 初始化值只能初始化一次useEffect 内部不能修改 stateuseEffect 依赖引用类型可能会出现死循环
React 18 新增 hooks
useTransition
使用useTransition来降低渲染优先级, 可以指定 UI 的渲染优先级哪些需要实时更新哪些需要延迟更新。
useDefferdValue
允许变量延时更新接收一个可选的延迟更新的最长时间
userId
使用 useId 可以生成客户端与服务端之间的唯一id 并且返回一个字符串。
useSyncExternalStore
可以使 React 在并发模式下保持自身 state 和来自 redux 的状态同步。
useInsertionEffect
useInsertionEffect 可以在布局副作用触发之前将元素插入到 DOM 中。