React Hooks (Proposal)

栏目: IOS · Android · 发布时间: 5年前

内容简介:在 React v16.7.0 alpha 版本里,提出了一个新的 Feature Proposal :Hooks ,对社区以及以后前端发展所带来的影响是巨大的。学习 Hooks 的知识需要对 React 生态有较深入的理解Hooks 是 React 内部组件中的一系列特殊函数,直观带来的改变是引入state、生命周期函数、或者其他 React 功能,无需使用 classes 编写组件(类语法带来的问题有很多),背后为前端带来更深入更普及的

在 React v16.7.0 alpha 版本里,提出了一个新的 Feature Proposal :Hooks ,对社区以及以后前端发展所带来的影响是巨大的。

学习 Hooks 的知识需要对 React 生态有较深入的理解

What is the Hooks ?

Hooks 是 React 内部组件中的一系列特殊函数,直观带来的改变是引入state、生命周期函数、或者其他 React 功能,无需使用 classes 编写组件(类语法带来的问题有很多),背后为前端带来更深入更普及的 functional programming 思想。

引入 Hooks 的动机

React 官方阐明了引入 Hooks 的动机,Hooks 出现前,我们编写 React 组件 会经常遇到的问题:

  1. It’s hard to reuse stateful logic between components
    • React 没有提供官方方案去解决 组件之间共享复用有状态逻辑 ,组件间逻辑的复用和数据传递就变得十分困难(必须一层一层往下传),所以我们使用 render propshigher-order components 来解决复用逻辑的同时引来了新的问题,一些无关 UI 的 wrapper 组件越来越多,嵌套组件越来越深,形成 wrapper hell ,虽然 React devTools 有过滤器来帮助我们更容易地调试。
    • 使用 Hooks 可以在不改变组件层次结构的情况下复用有状态逻辑 。可以利用 custom hooks,复用包含状态的逻辑,这些逻辑不再出现在组件树中,而是形成一个独立、可测试的单元,但仍然响应 React 在渲染之间的变化;社区之间分享 自定义hooks 更容易,hooks 就像插件一样。
  2. Complex components become hard to understand
    • 随着项目深入,我们逐渐会编写越来越复杂的逻辑在组件中,这导致了再生命周期函数内编写的逻辑非常臃肿,例如 添加监听器 ,我们需要在 componentDidMountcomponentWillUnmount 中分别编写添加与删除监听器的逻辑,而一般在 componentDidMount 中,我们也会编写 请求数据 的逻辑。各种功能不相关联的逻辑写在一起,而且相同功能的逻辑散落在不同函数内,这带来许多隐患以及调试上的困难
    • 使用 Hooks 可以 将相关联的逻辑code由组件拆分出来成更简单直观的函数(例如订阅事件、请求数据)
  3. Classes confuse both people and machines
    • React 官方认为 JS 的 Class 语法的学习成本很高,使用类语法,要必须清楚 this 在 JS 的工作方式,例如我们需要 绑定事件处理程序 (以何种方式绑定这里不是重点,个人推荐箭头函数形式);另外一些重要实践上,使用 Class 语法也带来诸多问题,详细参阅 classes-confuse-both-people-and-machines )
    • 使用 Hooks 可以 在无需编写 Class 语法的情况下 引入state、生命周期函数、或者其他 React 功能

实际上引入 Hooks 并不会给现有的代码带来问题

  1. 完全可选(将使用 Hooks 的选择权交给开发者)
  2. 向后兼容(不会有任何破坏性更改)
  3. 在可预见的未来内,不会从 React 中删除 类语法
  4. Hooks 并没有颠覆之前的 React 概念。相反,带来更直观的 API 实现相同的功能

编写 Hooks

目前主要的 Hooks :

  1. State hooks
  2. Effect hooks
  3. Custom hooks (自定义 hooks 用来复用包含状态的逻辑)

useState

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

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

使用 state hooksfunction components 中可以像上面代码这样,等同于Class语法的代码就不贴了。

值得一提的是,在 Hooks 出现之前,我们通常叫这样形式的组件为 stateless components or stateless function components ,但现在,有了 Hooks ,我们可以在这类组件中使用 state,所以改称 function components

  1. useState 的参数是 我们需要定义的 state 名的初始值(不必像以前一样,state 必须为 Object,如果我们想要创建两个state,就调用两次 useState)
  2. 返回值是包含两个值的数组,两个值分别为 当前状态更新它的函数 。(这里我们使用 array destructuring 的方式将值取出来。)

创建多个 state 就像这样

function ExampleWithManyStates() {
  // Declare multiple state variables!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
复制代码

this.setState 不同,更新状态总是替换它而不是合并它(也解决了很多之前合并带来的问题)

Functional updates

如果新的 state 值是依赖上一个 state 值来计算的,我们可以给 setState 传递一个函数参数,这个函数的参数为上一个 state 的值,返回值是更新后的 state 值,例如:

function Counter({initialCount}) {
  const [count, setCount] = useState(initialCount);
  return (
    <>
      Count: {count}
      <button onClick={() => setCount(0)}>Reset</button>
      <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
      <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
    </>
  );
}
复制代码

所以如果需要更新的 state 值为 Object,我们应该使用 object spread syntax

setState(prevState => {
  // Object.assign would also work
  return {...prevState, ...updatedValues};
});
复制代码

延迟初始化 state

如果初始化的值是需要大量计算得到的结果,可以使用函数代替,此函数只会在初始化阶段执行

const [state, setState] = useState(() => {
  const initialState = someExpensiveComputation(props);
  return initialState;
});
复制代码

useEffect

Effect 其实就是 请求数据,操作DOM,以及订阅事件等一系列 副作用/效果

而 useEffect 则是 之前 componentDidMountcomponentDidUpdatecomponentWillUnmount 的结合

React组件中有两种常见的 Effect:需要清理和不需要清理的 Effect

不需要清理的 Effect

import { 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>
  );
}
复制代码
  1. 将在每次渲染后执行 useEffect
  2. useEffect 写在 函数内部是为了直接访问到state值,利用了闭包的性质,不需要额外 API

需要清理的 Effect

import { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
复制代码

需要单独的 API 来执行清理逻辑。因为添加和删除订阅的逻辑是相关的,useEffect 旨在将其保持在一起。 如果 useEffect 返回一个函数,React 将在清理时执行它

清理的时机是 当组件卸载时 ,但,useEffect 会在每次渲染后运行而不仅仅是一次, 这就是 React 在下次执行 useEffect 之前还清除前一个 useEffect 的原因; Using the Effect Hook – React

如果要减少 useEffect 内并不是每次渲染都必要的逻辑,可以:

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes
复制代码

React 会比较两次渲染的 count 值,如果一样,就会跳过这次 useEffect

Custom Hooks

我们可以封装在多个组件可重用的包含状态的逻辑,例如

import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}
复制代码

useFriendStatus 就是一个我们写好的复用逻辑函数,供其他组件调用。

多个组件使用 相同自定义Hooks,它们的状态和效果是 独立隔离的,仅仅是逻辑的复用。因为本质是 调用 Custom Hooks 是调用 useStateuseEffect ,它们在一个组件调用很多次,彼此产生的状态也是完全独立的。

详细参见文档: Writing Custom Hooks – React


以上所述就是小编给大家介绍的《React Hooks (Proposal)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

算法导论(原书第3版)

算法导论(原书第3版)

Thomas H.Cormen、Charles E.Leiserson、Ronald L.Rivest、Clifford Stein / 殷建平、徐云、王刚、刘晓光、苏明、邹恒明、王宏志 / 机械工业出版社 / 2012-12 / 128.00元

在有关算法的书中,有一些叙述非常严谨,但不够全面;另一些涉及了大量的题材,但又缺乏严谨性。本书将严谨性和全面性融为一体,深入讨论各类算法,并着力使这些算法的设计和分析能为各个层次的读者接受。全书各章自成体系,可以作为独立的学习单元;算法以英语和伪代码的形式描述,具备初步程序设计经验的人就能看懂;说明和解释力求浅显易懂,不失深度和数学严谨性。 全书选材经典、内容丰富、结构合理、逻辑清晰,对本科......一起来看看 《算法导论(原书第3版)》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具