📅 GJ504b 的 React 进阶之路:Day 2
📅 GJ504b 的 React 进阶之路:Day 2
一、useEffect 基础认知:解决“副作用”问题
1. 核心作用
useEffect 专门处理 React 组件中非渲染逻辑的“副作用”,在代码中实战了 3 类核心副作用,对应代码如下:
// 1. DOM 操作(Counter 组件)—— 打印 DOM 元素内容
export default function Counter() {
const [count, setCount] = useState(0);
// 👇 副作用:操作 DOM 元素
useEffect(() =>{
console.log(document.querySelector('.count')?.innerText)
},[count])
// ...其余代码
}
// 2. 网络请求(ColorGet 组件)—— fetch 接口获取颜色
export default function ColorGet(){
const [color,setColor] = useState('')
const [flag,setFlag] = useState(false)
// 👇 副作用:网络请求
useEffect(()=>{
const controller = new AbortController()
if (!flag) return
fetch('https://api.liulongbin.top/v1/color',{signal:controller.signal})
// ...请求处理逻辑
},[flag])
// ...其余代码
}
// 3. 定时器(PatientTable 组件)—— setTimeout 模拟异步请求
export default function PatientTable(){
const[list,setList] = useState([]);
// 👇 副作用:定时器
useEffect(() =>{
const timer = setTimeout(() =>{
const mockPatient = [/* 模拟数据 */];
setList(mockPatient)
},1000);
// 清理函数
return () => clearTimeout(timer);
},[]);
// ...其余代码
}
2. 基础语法
useEffect(() => {
// 【副作用函数】:执行网络请求(核心逻辑)
const controller = new AbortController()
if (!flag) return
fetch('https://api.liulongbin.top/v1/color',{signal:controller.signal})
.then((res) =>res.json())
.then((res) =>{
console.log(res)
setColor(res.data.color)
})
.catch((err)=>console.log("消息:" + err.message))
// 【清理函数】:中止未完成的请求,避免内存泄漏
return () => controller.abort()
}, [flag]); // 依赖项数组
二、核心规则:依赖项数组的“优先级”
useEffect(() =>{
console.log(document.querySelector('.count')?.innerText)
},[])//1. 空数组的位置是依赖项,只会执行1次
useEffect(() =>{
console.log(document.querySelector('.count')?.innerText)
})//2. 但是如果不写依赖项就代表每次组件渲染后再执行
useEffect(() =>{
console.log(document.querySelector('.count')?.innerText)
},[count])//3. 只在组件渲染和判断count是否改变后再执行
避坑点
export default function Counter() {
const [count, setCount] = useState(0);
// ❌ 禁止:useEffect 内修改自身依赖项(会无限循环)
// 注释4:以下代码会导致无限循环
// useEffect(() =>{
// setCount((prev) =>prev + 1)
// console.log(document.querySelector('.count')?.innerText)
// },[count])
// ✅ 规范:多个副作用分开声明(注释5)
// 比如“DOM 监听”和“网络请求”分开写
useEffect(() => { /* DOM 操作 */ }, [count]);
useEffect(() => { /* 若有请求 */ }, []);
}
补充:React 严格模式的影响
export default function Counter() {
const [count, setCount] = useState(0);
// 👆 组件顶层代码:开发环境严格模式下会执行 2 次(比如直接写 console.log 会打印两次)
useEffect(() =>{
console.log(document.querySelector('.count')?.innerText)
},[count])
// 👆 useEffect 内代码:React 特殊处理,仅执行 1 次(初始渲染时)
}
三、进阶用法:清理函数(return 函数)
// ColorGet 组件中清理函数的触发时机注释
useEffect(()=>{
const controller = new AbortController()
if (!flag) return
fetch('https://api.liulongbin.top/v1/color',{signal:controller.signal})
// ...请求逻辑
/* 清理函数的触发时机:
1. 组件被卸载时
2. effect副作用函数被执行之前,先执行清理函数 */
return () => controller.abort()
},[flag])
四、实战落地:useEffect 结合业务逻辑
1. ColorGet 组件:条件触发网络请求
export default function ColorGet(){
const [color,setColor] = useState('')
const [flag,setFlag] = useState(false)
// 👇 核心:仅 flag 为 true 时发起请求
useEffect(()=>{
const controller = new AbortController()
if (!flag) return // 条件判断:flag 为 false 直接终止
fetch('https://api.liulongbin.top/v1/color',{signal:controller.signal})
.then((res) =>res.json())
.then((res) =>{
console.log(res)
setColor(res.data.color)
})
.catch((err)=>console.log("消息:" + err.message))
return () => controller.abort()
},[flag]) // 依赖 flag,点击按钮(flag 变化)时执行
return(
<>
<button onClick={()=>setFlag((prev) => !prev)}>Click it</button>
{flag && <p>color 的颜色是:{color}</p>}
</>
)
}


2. PatientTable 组件:挂载时模拟异步请求
export default function PatientTable(){
const[list,setList] = useState([]);
// 👇 依赖空数组:仅挂载时执行 1 次
useEffect(() =>{
const timer = setTimeout(() =>{
const mockPatient = [
{name:'张三',state:'已上链',age:18},
{name:'李四',state:'未上链',age:33},
{name:'王五',state:'已上链',age:16}
];
setList(mockPatient)
console.log('数据到了!')
},1000);
// 清理函数:避免组件卸载后定时器执行
return () => clearTimeout(timer);
},[]);
// 交互优化:加载中/数据展示
return (
<div>
<h3>最近访问者</h3>
{
list.length ===0 ?<p>正在调取数据</p> : (
<ul>{/* 渲染列表 */}</ul>
)
}
</div>
)
}


3. Counter 组件:监听状态变化操作 DOM
export default function Counter() {
const [count, setCount] = useState(0);
function add() {
setCount((count) =>count + 1);
}
// ❌ 直接顶层操作 DOM:无法实时更新
// console.log(document.querySelector('.count')?.innerText)
// ✅ useEffect 操作 DOM:确保拿到最新 DOM
useEffect(() =>{
console.log(document.querySelector('.count')?.innerText)
},[count])
return (
<div>
<div className="count">count 的值:{count}</div>
<button onClick={add}> + 1 </button>
</div>
);
}

核心要点回顾
useEffect核心是处理副作用(DOM/请求/定时器),依赖项数组决定执行时机:无依赖=每次渲染、空数组=仅挂载、特定状态=状态变化时执行;- 清理函数是“内存保护手段”:定时器要
clearTimeout、网络请求要abort,避免内存泄漏; - 实战技巧:通过
if (!flag) return条件判断控制副作用执行时机,贴合业务逻辑; - 严格模式特性:组件顶层代码执行 2 次,
useEffect内代码仅执行 1 次(开发环境)。
力扣
题目描述

解题(想不出来,最后看的题解)
还是js内置方法不够灵活应用
/**
* @param {string[]} strs
* @return {string[][]}
*/
var groupAnagrams = function(strs) {
const n = strs.length;
const map = new Map();
for(let i = 0;i<n;i++){
let arr = Array.from(strs[i]);//把字符串变成字符数组,便于后续排序等操作
arr.sort();
let key = arr.toString()//将排好序的字符数组转成字符串作为哈希表的键
let list = map.get(key) ?map.get(key):new Array();//将键存入分组数组list(有这个键就直接存放,没有就开辟新数组空间存放),相当与“指针”
list.push(strs[i]);//把与指针对应的值(原始值)存入对应数组
map.set(key,list);//把更新后的list数组和键放在map哈希表中
}
return Array.from(map.values());//返回想要的值部分
};

浙公网安备 33010602011771号