Hooks:尽享React特性 ,重塑开发体验
🎼 React 16.8 版本引入了 Hooks ,可以在不使用 Class 的情况下使用 React 特性。
Hooks 允许从函数组件 “hook into” React 状态和生命周期特性。
function Counter () {
const [count, setCount] = useState(0);
return (<>
<p>{count}</p>
<button onClick={() => setCount(count + 1)}> +1 </button>
</>)
}
为什么引入 Hooks ?
一个新的方案引入,一定是为了解决现存的问题。对于 Hooks 来说,就是为解决 Class 的诟病。
- 组件之间复用状态逻辑异常困难,存在“回调地狱”的风险 ==> render props 和 Hoc 高阶组件都需要重新构造组件。
- 复杂的组件难以理解及维护(状态逻辑及副作用堆积)==> 常见的,每个生命周期方法中包含了一组不相关的逻辑。
- 基于 Class 的组件,比较难以理解,且不能很好的控制范围,对于热更新不友好,优化路径不佳。
因此,引入了 Hooks:
- 使用 Hooks 可以从组件中提取有状态逻辑,这样就可以独立地对其进行测试并复用。其允许在不改变组件层次结构的情况下复用有状态逻辑。这样可以很容易在许多组件之间或与社区共享 Hook。
- 使用 Hooks 可以将一个组件拆分为更小的函数,而不是强制基于生命周期方法进行拆分。也可以选择使用 reduce 来管理组件的本地状态,以使其更可预测。
- Hooks 允许在不使用类的情况下更多地使用 React 的特性。从概念上讲,React 组件总是更接近于函数,不需要学习复杂的功能或响应式编程技术。
Hooks 是否可以完全取代 render props 和 Hoc 组件?1
答:不能,例如虚拟滚动组件需要具有 renderItem prop,以及可视化容器组件可能具有自己的DOM结构。
✔️ Hooks 让我们根据代码所做的,而不是生命周期方法名称来分割代码。React 组件一直更像是函数,而 Hooks 则拥抱了函数。
Hooks 使用规则(调用位置有限制)
✅ 在函数组件的顶层调用 Hooks
✅ 在 React 的函数组件或自定义Hooks中调用 Hook
下述以 useState(React 内置钩子) 为例:
// ✅ 在函数组件的顶层调用
function Counter () {
const [count, setCount] = useState(0);
}
// ✅ 在自定义Hooks的顶层调用
function useWindowWidth () {
const [width, setWidth] = useState(window.innerWidth);
}
不要在循环、条件、嵌套函数 或 try/catch/finally 块中调用。这样可以做到各个 Hook 在每一次渲染中,调用的顺序是一致的。
const [count, setCount] = useState(0);
数组结构语法允许我们为状态变量赋予不同的名称。这些名称不是 useState API 的一部分。
替代生命周期
constructor
: 函数组件不需要 constructor,可以通过useState
初始化(如果数据复杂,可以传入函数);getDerivedStateFromProps
:渲染过程更新shouldComponentUpdate
:使用React.memo
componentDidMount
,componentDidUpdate
,componentWillUnmount
:Effect Hooks 可以替代
示例:Class 形式:
class FriendStatusWithCounter extends React.Component {
constructor(props) {
super(props);
}
// 初始化:订阅
componentDidMount() {
ChatAPI.subscribeToFriendStatus(...);
}
// DOM更新:先取消再重新订阅
componentDidUpdate(prevProps) {
ChatAPI.unsubscribeFromFriendStatus(...);
ChatAPI.subscribeToFriendStatus(...);
}
// 卸载:取消订阅
componentWillUnmount() {
ChatAPI.unsubscribeFromFriendStatus(...);
}
}
Hooks 形式:
function FriendStatus(props) {
useEffect(() => {
// 订阅
ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
return () => {
// 取消
ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
}
})
}
如何获取 previous props 或 state ?
useEffect(() => {
ChatAPI.subscribeToFriendStatus(props.friend.id);
return () => ChatAPI.unsubscribeFromFriendStatus(props.friend.id);
}, [props.userId]);
在上面的示例中,如果 Id 从 3 => 4,ChatAPI.unsubscribeFromFriendStatus(3)
将首先运行,然后 ChatAPI.subscribeToFriendStatus(4)
将运行。不需要获取 “previous Id”,因为 clean up 函数将在闭包中捕获它。
➰或者可以将以前的 state 或 props 存储。
function ScrollView({row}) {
const [isScrollingDown, setIsScrollingDown] = useState(false);
// 存储之前值
const [prevRow, setPrevRow] = useState(null);
if (row !== prevRow) {
// 自上次渲染后更改
setIsScrollingDown(prevRow !== null && row > prevRow);
setPrevRow(row);
}
return `Scrolling down: ${isScrollingDown}`;
}
内置 Hooks
State Hook2
可以用于记住用户输入的信息。
- 使用
useState
声明可以直接更新的状态变量。 - 使用
useReducer
在 reducer 函数 中声明带有更新逻辑的 state 变量。
Context Hook
从祖先组件接收信息,而无需将其作为 props 传递。
- 使用
useContext
读取订阅上下文。
// ① 创建context
const ThemeContext = createContext(null);
export default () => {
const [color, setColor] = useState('red');
return (<>
{/* ② 使用 context provider 进行包裹 */}
<ThemeContext.Provider value={color}>
<MyText />
</ThemeContext.Provider>
</>)
}
function MyText() {
// ③ 使用
const color = useContext(ThemeContext);
return (<>
<div>{color}</div>
</>)
}
Ref Hook 3
保存一些不用于渲染的信息,比如 DOM 节点或 timeout ID。
- 使用
useRef
声明 ref。你可以在其中保存任何值,但最常用于保存 DOM 节点。 - 使用
useImperativeHandle
自定义从组件中暴露的 ref,但是很少使用。
Effect Hook 4
连接到外部系统并与之同步。这包括处理网络、浏览器、DOM、动画、使用不同 UI 库编写的小部件以及其他非 React 代码。
- 使用
useEffect
将组件连接到外部系统。 useLayoutEffect
在浏览器重新绘制屏幕前执行,可以在此处测量布局。useInsertionEffect
在 React 对 DOM 进行更改之前触发,库可以在此处插入动态 CSS。
性能 Hook
优化重新渲染性能的一种常见方法是跳过不必要的工作。例如,可以告诉 React 重用缓存的计算结果,或者如果数据自上次渲染以来没有更改,则跳过重新渲染:
- 使用
useMemo
缓存计算代价昂贵的计算结果。 - 使用
useCallback
将函数传递给优化组件之前缓存函数定义。
将必须同步的阻塞更新(比如使用输入法输入内容)与不需要阻塞用户界面的非阻塞更新(比如更新图表)分离以提高性能:
useTransition
允许将状态转换标记为非阻塞,并允许其他更新中断它。useDeferredValue
允许延迟更新 UI 的非关键部分,以让其他部分先更新。
其他 Hook
- 使用
useDebugValue
自定义 React 开发者工具为自定义 Hook 添加的标签。 - 使用
useId
将唯一的 ID 与组件相关联,其通常与可访问性 API 一起使用。 - 使用
useSyncExternalStore
订阅外部 store。
https://legacy.reactjs.org/docs/hooks-faq.html#which-versions-of-react-include-hooks react hook FAQ ↩︎
https://blog.csdn.net/ligang2585116/article/details/136458885 总结:React 中的 state 状态 ↩︎
https://blog.csdn.net/ligang2585116/article/details/136626405 脱围:使用 ref 保存值及操作DOM ↩︎
https://blog.csdn.net/ligang2585116/article/details/136880009?spm=1001.2014.3001.5501 Effect:由渲染本身引起的副作用 ↩︎
原文地址:https://blog.csdn.net/ligang2585116/article/details/137631509
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!