Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
理解:hook是react提供的函数API
官方提供的hook
基础hook
useState API
const [state, setState] = useState(initialState);
//返回state值 以及更新state的方法
在初始渲染期间,返回的状态 (state) 与传入的第一个参数 (initialState) 值相同。
setState 函数用于更新 state。它接收一个新的 state 值并将组件的一次重新渲染加入队列。
案例:
//引入 hook
import { useState } from "react";
//16.8
//useState 给函数组件提供state状态值
//useState 返回数组 [state状态值,更新状态值的方法]
export default () => {
//定义状态 useState参数为初始值
let [num, setNum] = useState(0);
console.log("渲染",num);
//定义+-事件
//匿名函数写法
// let handler = () => {};
function handler(type) {
switch (type) {
case "decrement":
//--
num--;
break;
case "increment":
//++
num++;
break;
}
setNum(num);
}
return (
<>
<button onClick={handler.bind(null, "decrement")}>-</button>
<div>数量:{num}</div>
<button onClick={handler.bind(null, "increment")}>+</button>
</>
);
};
//state状态值num===初始状态值
//state状态值首次编译创建一次。更新state状态值不会重新定义
//案例中存在num++ 后置++ --
//整个程序运行存在异常。
函数组件中定义状态值
//定义状态 useState参数为初始值
let [num, setNum] = useState(0);
let [isShow, setShow] = useState(true);
let [arr, setArray] = useState([0, 1, 2, 3, 4]);
let [stu, setStu] = useState({
name: "小花",
age: 18,
});
let [city, setCity] = useState([{ name: "西安市" }, { name: "咸阳市" }]);
注意使用useState定义数据state
//1.state状态值为普通变量 可以直接修改 可以让函数组件更新
//2.如果函数组件中定义的数据为对象或者数组
//对象某个key修改
stu.name = "小黑";
setStu(stu)
//数组某个索引值修改
arr[0] = 11;
setArray(arr);
//以上两种写法不会导致函数组件更新
//底层监听不到当前数据在变化,因为引用链没有断掉。
建议断链:
setStu({ ...stu, name: "小黑" });
arr[0]=11;
setArray([...arr]);
react中对象检测机制:
React 使用 Object.is 比较算法 来比较 state。 所以需要断链操作。
与 class 组件中的 setState 方法不同,useState 不会自动合并更新对象
函数组件中产生覆盖。
你可以用函数式的 setState 结合展开运算符来达到合并更新对象的效果。
意思是如果需要类似setState 对象合并。 使用函数式来处理。
//函数式写法 useState
// setStu({ ...stu, name: "小黑" });
setStu((state) => {
//业务逻辑代码
return { ...stu, name: "xiaohei" };
});
useEffect
类似周期函数 常用hook 主要功能是用来处理副作用
useEffect(() => {
console.log("挂载");
});
//以上的这种用法 等待jsx模板编译挂载到页面之后执行外部的函数(类似挂载完成)
//当前函数组件数据更新 可以当作更新完成
//下面这种写法 外部函数执行一致。 内部返回的函数为处理副作用函数。
//首次编译 处理副作用函数不执行。()
useEffect(() => {
console.log("挂载");
//返回的函数为处理副作用函数
return function (){
console.log("处理副作用");
}
});
//当前函数组件数据更新 函数组件重新编译 useEffect继续执行---先执行上次的副作用处理
//作用:为防止内存泄漏,清除函数会在组件卸载前执行
useEffect(() => {
console.log("挂载");
//返回的函数为处理副作用函数
return function () {
console.log("处理副作用");
};
});
例如:
useEffect(() => {
console.log("挂载");
let time = setInterval(() => {
console.log("输出");
}, 1000);
//返回的函数为处理副作用函数
return function () {
console.log("处理副作用");
clearInterval(time);
};
});
//如果在子组件中使用useEffect 处理副作用
useEffect(() => {
console.log("挂载完成或者更新完成");
//处理副作用和卸载之前
return () => {
console.log("处理副作用");
};
});
console.log("渲染");
//考虑当前组件卸载 处理副作用函数可以当作卸载之前使用
//useEffect 可以代替组件的挂载完成和更新完成和卸载之前 三个周期。
useEffect 外部处理函数:与 componentDidMount、componentDidUpdate 不同的是,在浏览器完成布局与绘制之后,传给 useEffect 的函数会延迟调用。
演示useEffect的使用场景
类似挂载:
export default () => {
//类似挂载完成周期 useEffect的函数是在挂载页面之后延迟执行
useEffect(()=>{
console.log("执行");
});
console.log("渲染");
return (
<>
<div>测试</div>
</>
);
};
类似更新:
export default () => {
let [num, setNum] = useState(0);
useEffect(() => {
console.log("执行");
});
let update = () => {
num++;
setNum(num);
};
console.log("渲染");
return (
<>
<div>测试-{num}</div>
<button onClick={update}>更新</button>
</>
);
};
//修改当前组件state 组件更新 执行useEffect中函数--功能类似更新完成
类似卸载之前:
官方解释是卸载之前处理副作用函数。处理当前组件副作用。
import { useEffect } from "react";
export default () => {
useEffect(() => {
console.log("执行");
return function () {
console.log("处理副作用");
};
});
console.log("渲染");
return (
<>
<div>菜单</div>
</>
);
};
//子组件首次挂载产生一个副作用处理函数
//直接子组件卸载 执行上次产生的副作用函数(类似卸载之前)
effect 的条件执行
默认情况下,effect 会在每轮组件渲染完成后执行。这样的话,一旦 effect 的依赖发生变化,它就会被重新创建。
在函数组件中具体到某个状态发生变化useEffect才执行。
给useEffect添加条件(让useEffect存在依赖项,依赖项发生变化的时候useEffect才重新定义执行)
useEffect 参数二:[]
用法:
useEffect(() => {
console.log("执行");
//定义计时器
let timer = setInterval(() => {
console.log("计时器");
}, 500);
return function () {
console.log("处理副作用");
clearInterval(timer);
};
}, [num]);
//依赖[]
useEffect(() => {
console.log("执行");
//定义计时器
let timer = setInterval(() => {
console.log("计时器");
}, 500);
return function () {
console.log("处理副作用");
clearInterval(timer);
};
}, []);
//依赖值为空 默认首次挂载之后执行其余不执行
//存在多个依赖项
useEffect(() => {
console.log("执行");
//定义计时器
let timer = setInterval(() => {
console.log("计时器");
}, 500);
return function () {
console.log("处理副作用");
clearInterval(timer);
};
}, [num,name]);
useEffect用法
调网络为例:
//引入获取验证码接口
import { useEffect } from "react";
import { getCaptcha } from "../network/user";
export default () => {
useEffect(async () => {
let res = await getCaptcha();
console.log(res);
}, []);
return (
<>
<div>登录界面</div>
</>
);
};
//官方警告
//引入获取验证码接口
import { useEffect } from "react";
import { getCaptcha } from "../network/user";
export default () => {
useEffect(() => {
async function request() {
let res = await getCaptcha();
console.log(res);
}
request();
}, []);
return (
<>
<div>登录界面</div>
</>
);
};