功能优点
- Hook使你在无需修改组件结构的情况下复用状态逻辑。
- class缺点:不能很好的压缩,并且会使热重载出现不稳定的情况,比较"重"。hook更简洁,代码量少,官方推荐。
useEffect
- 作用:指定一个函数,组件每渲染(加载和更新)一次,该函数就自动执行一次(React的class组件没有提供这样的方法。)
- 与class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API
- 解决了class中生命周期函数经常包含不相关的逻辑,但又把相关逻辑分离到了几个不同方法中的问题
class的写法:
componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
}
componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
}
hook的写法
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
- 如果不希望useEffect()每次渲染都执行,这时可以使用它的第二个参数,使用一个数组指定函数的依赖项,只有依赖项发生变化(===比较符),才会重新渲染。
- 依赖项数组不会作为参数传给回调函数。
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // 仅在 count 更改时更新
useEffect(() => {
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
};
});
- 执行时机:浏览器完成布局与绘制之后,在一个延迟事件中被调用
useState
- 通过在函数组件里调用它来给组件添加一些内部state。React 会在重复渲染时保留这个 state。
- useState 会返回一对值:当前状态和一个让你更新它的函数,你可以在事件处理函数中或其他一些地方调用这个函数。它类似 class 组件的 this.setState,但是它不会把新的 state 和旧的 state 进行合并。useState 唯一的参数就是初始 state
import React, { useState } from 'react';
function Example() {
// 声明一个叫 "count" 的 state 变量
const [count, setCount] = useState(0);
//可以直接用 count:
<p>You clicked {count} times</p>
//更新 State
<button onClick={() => setCount(count + 1)}>
Click me
</button>
- 如果新的 state 需要通过使用先前的 state 计算得出,那么可以将函数传递给 setState
const [count, setCount] = useState(initialCount);
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
- 如果你的更新函数返回值与当前 state 完全相同(Object.is 比较算法),则随后的重渲染会被完全跳过。
- 与 class 组件中的 setState 方法不同,useState 不会自动合并更新对象。你可以用函数式的 setState 结合展开运算符来达到合并更新对象的效果。
const [state, setState] = useState({});
setState(prevState => {
// 也可以使用 Object.assign
return {...prevState, ...updatedValues};
});
自定义hook
- 自定义 Hook,可以将组件逻辑提取到可重用的函数中。每次使用自定义 Hook 时,其中的所有state和副作用都是完全隔离的。
- 自定义 Hook 是一个函数,其名称以 “use” 开头(否则React将无法自动检查你的Hook是否违反了Hook的规则),函数内部可以调用其他的Hook
额外的 Hook
useReducer
- useState 的替代方案
- 适用情况:state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等
useMemo
- 传入 useMemo 的函数会在渲染期间执行,请不要在这个函数内部执行不应该在渲染期间内执行的操作,诸如副作用这类的操作属于 useEffect 的适用范畴,而不是 useMemo
- 可以把 useMemo 作为性能优化的手段
useCallback
useRef
一个常见的用例便是命令式地访问子组件:
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
Hook 规则
- 只在最顶层使用 Hook,以及任何 return 之前调用,不要在循环,条件或嵌套函数中调用 Hook,这样可以确保Hook在每一次渲染中都按照同样的顺序被调用。
- 只在React函数或自定义Hook中调用 Hook,不要在普通的JavaScript函数中调用Hook
- 如果我们想要有条件地执行一个effect
- 能在React的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用
|