亲宝软件园·资讯

展开

React Hook上车

奔跑的瓜牛 人气:0
React Hook 是 v16.8 的新功能,自诞生以来,受到广泛的好评,在 React 版本更新中具有里程碑的意义。现在都2020年了,再不上车 React Hook 就真的 out 了...
### Hook 动机 本着“存在即合理”的原则,我们先来康康 Hook 为我们解决了哪些问题?Hook 有哪些优势呢?

在编写 React 组件时,我们更喜欢函数组件,而不是 class 组件。

因为函数组件代码更少,结构更清晰,不容易产生 bug。但是,函数组件没办法使用状态,只能作为展示组件(就是个花瓶...哎)。
**
**有了 Hook,我们就能在函数组件中使用状态了**。毫不夸张的说,以后的组件都可以用函数组件 + Hook 来写。

**class 组件的问题:** - **状态逻辑难复用:**在组件之间复用状态逻辑很难,一般会用到 **render props** (**渲染属性**)或者 **HOC**(**高阶组件**)。但无论是渲染属性,还是高阶组件,都会在原先的组件外包裹一层父容器(一般都是 div 元素),**导致层级冗余** - **生命周期** - **多而善变的生命周期**:用 React 开发的你一定被那些杂乱多变的生命周期恶心过,声明周期多就不说了,随着版本的变动会经常变化,导致升级 React 版本时很烦 - **生命周期逻辑混乱:**在生命周期函数中混杂不相干的逻辑(如:在 `componentDidMount` 中注册事件以及其他的逻辑,在 `componentWillUnmount` 中卸载事件,这样分散不集中的写法,很容易写出 bug ) - **class 组件难以拆分**:class 组件中到处都是对状态的访问和处理,导致组件难以拆分成更小的组件 - **this 指向问题:**class 组件中的 this 指向问题绝对让人头疼,需要我们手动小心翼翼地去绑定 this,一不小心就会出现 bug。
**Hook 优势:** - 优化 class 组件的问题 - 能在无需修改组件结构的情况下复用状态逻辑(自定义 Hook ) - 能将组件中相互关联的部分拆分成更小的函数(比如设置订阅或请求数据) - **副作用的关注点分离**:**副作用指那些没有发生在数据向视图转换过程中的逻辑,如 `ajax` 请求、访问原生`dom` 元素、本地持久化缓存、绑定/解绑事件、添加订阅、设置定时器、记录日志等**。以往这些副作用都是写在类组件生命周期函数中的。而 `useEffect` 在全部渲染完毕后才会执行,`useLayoutEffect` 会在浏览器 `layout` 之后,`painting` 之前执行 ### Hook 规则 Hook 可以让你在不编写 class 组件的情况下使用 state 以及其他的 React 特性。但是,有些规则是我们需要准守的:
- **只能在****函数内部的最外层****调用 Hook
不要在循环,条件或嵌套函数中调用 Hook,** 确保总是在你的 React 函数的最顶层调用他们。遵守这条规则,你就能确保 Hook 在每一次渲染中都按照同样的顺序被调用。这让 React 能够在多次的 `useState` 和 `useEffect` 调用之间保持 hook 状态的正确 - **只能在 React 的****函数组件(非 class组件)****中调用 Hook
不要在普通的 JavaScript 函数或 class 组件中调用 Hook。**你可以: - 在 React 的函数组件中调用 Hook - 在自定义 Hook 中调用其他 Hook
ok,到此为止,我们已经了解 Hook 有哪些优势了。

下面,我们开始认识最常用的两个 Hook API—— useState、useEffect。

这两个API很好理解,而且很实用,弄懂能处理80%的业务场景。本文不会涉及太复杂的操作,仅仅作为入门。 ### useState 先来看一段简单的 Hook 代码: ```javascript import React, { useState } from 'react'; function Example() { // 声明一个叫 "count" 的 state 变量 const [count, setCount] = useState(0); return (

You clicked {count} times

); } ``` 我们将通过将这段代码与一个等价的 class 示例进行比较来开始学习 Hook。 等价的 class 组件示例: ```javascript class Example extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } render() { return (

You clicked {this.state.count} times

); } } ``` 很简单的一个加1计数器,Hook 写法比 class 组件是不是简洁了很多。

下面,我们来分析如何使用 useState Hook... ```javascript // 第一步:从 react 库中引入 useState Hook import React, { useState } from 'react'; function Example() { /* 第二步:通过调用 useState Hook 声明了一个新的 state 变量。 * 它返回一对值(数组)解构到我们命名的变量上。 * 第一个返回的是状态 count,它存储的是点击次数。我们通过传 0 作为 useState 唯一的参数来将其初始化 0。 * 第二个返回的值本身就是一个函数。它让我们可以更新 count 的值,所以我们叫它 setCount。 */ const [count, setCount] = useState(0); // 声明一个叫 "count" 的 state 变量 return (
// 第三步:读取 state,即count

You clicked {count} times

// 第四步:更新 state,通过 setCount()
); } ``` 通过上面的分析,我们可以看到使用 useState Hook 管理状态简直太爽了。不用写繁琐的 class 组件,不用担心 this 指向,代码是如此的清晰。

如何使用多个 state 变量:
将 state 变量声明为一对 `[something, setSomething]` 也很方便,因为如果我们想使用多个 state 变量,它允许我们给不同的 state 变量取不同的名称: ```javascript function ExampleWithManyStates() { // 声明多个 state 变量 const [age, setAge] = useState(42); const [fruit, setFruit] = useState('banana'); const [todos, setTodos] = useState([{ text: '学习 Hook' }]); ... ``` 在以上组件中,我们有局部变量 `age`,`fruit` 和 `todos`,并且我们可以单独更新它们: ```javascript function handleOrangeClick() { // 和 this.setState({ fruit: 'orange' }) 类似 setFruit('orange'); } ``` 你**不必**使用多个 state 变量。State 变量可以很好地存储对象和数组,因此,你仍然可以将相关数据分为一组。然而,不像 class 中的 `this.setState`,更新 state 变量总是_替换_它而不是合并它。
> **注意** > 你可能想知道:为什么叫 `useState` 而不叫 `createState`? > “Create” 可能不是很准确,因为** state 只在组件首次渲染的时候被创建**。在下一次重新渲染时,`useState` 返回给我们当前的 state。否则它就不是 “state”了!这也是 Hook 的名字_总是_以 `use`开头的一个原因。 ### useEffect Effect Hook定义:useEffect 传入一个 callback 函数 ```javascript useEffect(effect: React.EffectCallback, deps?: ReadonlyArray | undefined) ``` Effect Hook作用:处理函数组件中的副作用,如异步操作、延迟操作等,可以替代Class Component的`componentDidMount`、`componentDidUpdate`、`componentWillUnmount`等生命周期。 - effect(副作用):指那些没有发生在数据向视图转换过程中的逻辑,如 `ajax` 请求、访问原生`dom` 元素、本地持久化缓存、绑定/解绑事件、添加订阅、设置定时器、记录日志等。 - 副作用操作可以分两类:需要清除的和不需要清除的。 - useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。**它和 class 组件中的 `componentDidMount`、`componentDidUpdate` 和 `componentWillUnmount` 具有相同的用途**,只不过被合并成了一个 API - useEffect 接收一个函数,**该函数会在组件渲染到屏幕之后才执行**。该函数有要求:**要么返回一个能清除副作用的函数,要么就不返回任何内容** - 与 `componentDidMount` 或 `componentDidUpdate` 不同,使用 useEffect 调度的 effect 不会阻塞浏览器更新屏幕,这让你的应用看起来响应更快。大多数情况下,effect 不需要同步地执行。在个别情况下(例如测量布局),有单独的 useLayoutEffect Hook 供你使用,其 API 与 useEffect 相同
useEffect 使用示例: ```javascript import React, { useState, useEffect } from 'react'; function Example() { const [count, setCount] = useState(0); // 类似 componentDidMount 和 componentDidUpdate useEffect(() => { // 使用浏览器 API 去更新 document 标题 document.title = `You clicked ${count} times`; }); // 类似 componentDidMount useEffect(() => { // 使用浏览器 API 去更新 document 标题 document.title = `You clicked ${count} times`; }, []); // 慎用!监听空数组,当 callback 使用到 state 或 props 时最好不要用,因为只能获取初始化的数据 // 返回一个函数用于清除操作 useEffect(() => { document.title = `You clicked ${count} times`; window.addEventListener('load', loadHandle); // loadHandle 函数定义省略 return () => { window.removeEventListener('load', loadHandle); // 执行清理:callback 下一次执行前调用 }; }, [count]); // 只有当count的值发生变化时,才会重新执行 callback return (

You clicked {count} times

); } ```
useEffect 用法很简单,但是有两个地方需要特别注意: - deps 参数很重要 - **useEffect 可以接受第二个参数 deps,用于在 re-render 时判断是否重新执行 callback** - deps 数组项必须是 mutable 的,比如:不能也不必传 useRef、dispatch 等 - deps 的比较是**浅比较**(参阅[源码](https://link.zhihu.com/?target=https%3A//github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.js%23L326)),传入对象、函数是无意义 - 作为最佳实践,**使用 useEffect 时请尽可能都传 deps** - 清除副作用 - **useEffect 传入的 callback 要么返回一个清除副作用的函数,要么什么都不返回**。所以,callback 不能用 async 函数(面试题:如何在 useEffect 中使用 async 函数) - useEffect 传入的 callback 返回一个函数,在下一次执行 callback 前将会执行这个函数,从而达到清理 effect 的效果
useEffect 的用法大概就是这样的,有一些坑和更复杂操作这里没有涉及。当然,要深入理解的话需要去啃源码了,这里不做过多的解释。
> **Hook 核心知识点:闭包** > 当你在使用 Hook 遇到问题时,请先考虑是否由于闭包引起的。这将帮助你快速排查问题。 ### 总结 Hook 让我们可以在函数组件中使用状态state,函数组件一统 React 的时代来了,这很棒。

Hook 可以让我们摒弃那些繁琐的生命周期、不用考虑 this 的指向、复用逻辑也不用写HOC了,这很棒。

Hook 还有更多 API 等着我们去探索,同时也支持自定义 Hook。

Hook 发车啦,用过都说好...

参考:
[Hook 官方文档](https://react.docschina.orghttps://img.qb5200.com/download-x/docs/hooks-intro.html)
[30分钟精通React Hooks](https://juejin.im/post/5be3ea136fb9a049f9121014)
[React Hooks完全上手指南](https://juejin.im/post/5e67143ae51d452717263c13)
**

加载全部内容

相关教程
猜你喜欢
用户评论