概述
1. 为什么使用 hook
class 组件中的 this 难以理解,且 class 不能很好的压缩,并且会使热重载出现不稳定的情况。
所以 hook 就为解决这些问题而来:
避免地狱式嵌套,可读性提高。
函数式组件,比 class 更容易理解。
class 组件生命周期太多太复杂,使函数组件存在状态。
解决 HOC 和 Render Props 的缺点。
UI 和 逻辑更容易分离
2. Hook的一些API
我来介绍一下,hook的一些常用的api
2.1 useState
使用状态
const [data,setData] = useState("默认值")
注意事项 1:不可局部更新
如果 state 是一个对象,能否部分 setState?
答案是不行,因为 setState 不会帮我们合并属性
那么 useReducer 会合并属性吗?也不会!
因为 React 认为这应该是你自己要做的事情
注意事项 2:地址要变
setState(obj)如果 obj 地址不变,那么 React 就认为数据没有变化,不会更新视图
useState 接受函数
const [state, setState] = useState(() => {return initialState}) //该函数返回初始 state,且只执行一次
2.2 useReducer
用来践行 Flux/Redux 思想
一、创建初始值 initialState
二、创建所有操作 reducer(state, action)
三、传给 userReducer,得到读和写 API
四、调用写({type:"操作类型"})
如何代替 Redux
一、将数据集中在一个 store 对象
二、将所有操作集中在 reducer
三、创建一个 Context
四、创建对数据的读取 API
五、将第四步的内容放到第三步的 Context
六、用 Context.Provider 将 Context 提供给所有组件
七、各个组件用 useContext 获取读写 API
2.3 useContext
全局变量是全局的上下文
上下文是局部的全局变量
使用方法
一、使用 C = createContext(initial) 创建上下文
二、使用 <C.Provider> 圈定作用域
三、在作用域内使用 useContext(C)来使用上下文
2.3 useEffect
副作用
对环境的改变即为副作用,如修改 document.title
但我们不一定非要把副作用放在 useEffect 里面
实际上叫做 afterRender 更好,每次 render 后执行
用途
一、作为 componentDidMount 使用,[ ] 作第二个参数
二、作为 componentDidUpdate 使用,可指定依赖
三、作为 componentWillUnmount 使用,通过 return
四、以上三种用途可同时存在
// 作为 componentDidMount 使用,[] 作为第二个参数
useEffect(() => {
console.log("第一次渲染执行这句话");
}, []); // [] 里面的变量变化时执行 => 不会执行
// 作为 componentDidUpdate 使用,可指定依赖 n
useEffect(() => {
console.log("n变化时执行这句话");
}, [n]); // n 变化时执行
useEffect(() => {
console.log("任何一个state变化时都会执行");
});
// 作为 componentDidUpdate 使用,可指定依赖 n
useEffect(() => {
const timer = setInterval(() => {
console.log("hi");
}, 1000);
return () => {
setTimeout(() => {
window.clearInterval(timer);
}, 10000);
};
},[]);
特点
如果同时存在多个 useEffect,会按照出现次序执行
2.4 useLayoutEffect
布局副作用
useEffect 在浏览器渲染完成后执行
useLayoutEffect 在浏览器渲染前执行
特点
useLayoutEffect 总比 useEffect 先执行
useLayoutEffect 里的任务最好影响了 Layout
/* useLayoutEffect比useEffect先执行 */
function App2() {
const [n, setN] = useState(0)
const onClick = () => {
setN(i => i + 1)
}
//执行顺序打印出 2、3、1
useEffect(() => {
console.log(1)
})
useLayoutEffect(() => {
console.log(2)
})
useLayoutEffect(() => {
console.log(3)
})
return (
<div className="App">
<h1>n: {n}</h1>
<button onClick={onClick}>Click</button>
</div>
);
}
经验
为了用户体验,优先使用 useEffect (优先渲染)
2.5 useMemo
特点
第一个参数是 () => value
第二个参数是依赖 [m, n]
只有当依赖变化时,才会计算出新的 value
如果依赖不变,那么就重用之前的 value
这不就是 Vue 2 的 computed 吗?
注意
如果你的 value 是一个函数,那么你就要写成 useMemo(() => x => console.log(x))
这是一个返回函数的函数
是不是很难用?于是就有了 useCallback
2.6 useCallback
用法
useCallback(x => console.log(x), [m]) 等价于
useMemo( () => x => console.log(x), [m])
2.7 forwardRef
useRef
可以用来引用 DOM 对象
也可以用来引用普通对象
forwardRef
props 无法传递 ref 属性
function App(){
const buttonRef = useRef(null)
return (
<div>
<Button ref={buttonRef}>按钮</Button>
{/* 控制台报错:
Warning: Function components cannot be given refs.
Attempts to access this ref will fail.
Did you mean to use React.forwardRef()?
*/}
</div>
)
}
const Button = (props) => {
console.log(props) // {ref: undefined, children: "按钮"}
return <button {...props} />
}
实现 ref 的传递:由于 props 不包含 ref,所以需要 forwardRef
import React, {forwardRef, useRef} from 'react';
function App(){
const buttonRef = useRef(null)
return (
<div>
<Button ref={buttonRef}>按钮</Button2>
</div>
)
}
const Button = forwardRef((props, ref) => {
console.log(ref) //可以拿到ref对button的引用,forwardRef仅限于函数组件,class 组件是默认可以使用 ref 的
return <button ref={ref} {...props} />;
})
最后
以上就是外向毛衣为你收集整理的React Hook的全部内容,希望文章能够帮你解决React Hook所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复