首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >React进阶篇(六)React Hook

React进阶篇(六)React Hook

作者头像
娜姐
发布2020-12-11 16:12:57
发布2020-12-11 16:12:57
1.7K00
代码可运行
举报
文章被收录于专栏:娜姐聊前端娜姐聊前端
运行总次数:0
代码可运行

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。

例子:

代码语言:javascript
代码运行次数:0
运行
复制
import React, { useState } from 'react';

function Example() {
  // 声明一个新的叫做 “count” 的 state 变量
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

上面的例子里,useState 就是一个 Hook。

1. 什么是 Hook?

Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数。Hook 不能在 class 组件中使用。 React 内置了一些像 useState 这样的 Hook。你也可以创建你自己的 Hook 来复用不同组件之间的状态逻辑。

内置Hook:

  • useState
  • useEffect
  • useContext
  • useReducer
  • useCallback
  • useMemo
  • useRef
  • useImperativeHandle
  • useLayoutEffect
  • useDebugValue

下面只介绍前两种Hook。

2. State Hook

useState 与 class 里面的 this.state 提供的功能完全相同。一般来说,在函数退出后变量就就会”消失”,而 state 中的变量会被 React 保留(类似JS闭包)。

useState的每次调用都有一个完全独立的 state —— 因此你可以在单个组件中多次调用同一个自定义 Hook。如下:

代码语言:javascript
代码运行次数:0
运行
复制
// 声明多个 state 变量!
const [age, setAge] = useState(42);
const [fruit, setFruit] = useState('banana');
const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

使用步骤:

1).声明 State 变量
代码语言:javascript
代码运行次数:0
运行
复制
import React, { useState } from 'react';

function Example() {
  // 声明一个叫 "count" 的 state 变量
  const [count, setCount] = useState(0);
} 
2).读取 State
代码语言:javascript
代码运行次数:0
运行
复制
 <p>You clicked {count} times</p>
3).更新 State
代码语言:javascript
代码运行次数:0
运行
复制
<button onClick={() => setCount(count + 1)}>
    Click me
</button>

3. Effect Hook

useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。

下面的例子实现两个功能:

  1. 在title上面显示点击次数
  2. 订阅好友在线状态,并在实现取消订阅功能
代码语言:javascript
代码运行次数:0
运行
复制
import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // 对应类实现 componentDidMount 和 componentDidUpdate
    document.title = `You clicked ${count} times`;
  });

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    // 对应类实现 componentDidMount 和 componentWillUnmount
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
  1. useEffect 做了什么? 通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作。React 会保存你传递的函数(我们将它称之为 “effect”),并且在执行 DOM 更新之后调用它。
  2. useEffect 会在每次渲染后都执行吗? 是的,默认情况下,它在第一次渲染之后和每次更新之后都会执行。
  3. 为什么要在 effect 中返回一个函数? 这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数(类似componentWillUnmount函数)。如此可以将添加和移除订阅的逻辑放在一起。它们都属于 effect 的一部分。
  4. React 何时清除 effect? React 会在组件卸载的时候执行清除操作。而effect 在每次渲染的时候都会执行。这就是为什么 React 会在执行当前 effect 之前对上一个 effect 进行清除。
  5. 可以使用多个effect? 当然可以。如上面的例子,你可以使用多个effect封装不同的逻辑。
3.1 通过跳过 Effect 进行性能优化

因为每次更新的时候都要运行 effect(类似运行componentDidUpdate),所以,如果状态并没改变,如何让React跳过effect的调用呢?

如果是componentDidUpdate,我们会利用prevProps 或 prevState:

代码语言:javascript
代码运行次数:0
运行
复制
componentDidUpdate(prevProps, prevState) {
  if (prevState.count !== this.state.count) {
    document.title = `You clicked ${this.state.count} times`;
  }
}

useEffect中,我们只要在该API中传入第二个数组参数即可:

代码语言:javascript
代码运行次数:0
运行
复制
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);
  };
}, [props.friend.id]); // 仅在 props.friend.id 发生变化时,重新订阅

数值是全等比较,count1 === count2

利用useEffect的第二个参数,可以模拟componentDidMount函数,如下:

代码语言:javascript
代码运行次数:0
运行
复制
useEffect(()=>{
   // 只有第一次渲染mount时,才会被调用,相当于componentDidMount
}, [1])
3.2 useEffect优势

与 componentDidMount 或 componentDidUpdate 不同,使用 useEffect 调度的 effect 不会阻塞浏览器更新屏幕,这让你的应用看起来响应更快。大多数情况下,effect 不需要同步地执行。

  • useEffect 在渲染结束时执行,所以不会阻塞浏览器渲染进程,所以使用 Function Component 写的项目一般都有用更好的性能。
  • 符合 React Fiber 的理念,因为 Fiber 会根据情况暂停或插队执行不同组件的 Render,如果代码遵循了 Capture Value 的特性,在 Fiber 环境下会保证值的安全访问,同时弱化生命周期也能解决中断执行时带来的问题。
3.3 useEffect其他注意点
  • useEffect 不会在服务端渲染时执行。
  • 由于在 DOM 执行完毕后才执行,所以能保证拿到状态生效后的 DOM 属性。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 什么是 Hook?
  • 2. State Hook
    • 1).声明 State 变量
    • 2).读取 State
    • 3).更新 State
  • 3. Effect Hook
    • 3.1 通过跳过 Effect 进行性能优化
    • 3.2 useEffect优势
    • 3.3 useEffect其他注意点
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档