Hooks一览

在看了React Hooks的文档之后,本英语渣渣竟然突然有了想要翻译一下这篇文档的冲动,于是就首次尝试翻译第一篇英文文档,原文Hooks at a Glance

本文首发于我的博客libx.top

Hooks是一个React中的新提案,他可以让你在不使用Class的情况下使用state和其他的React特性。Hooks 目前已经发布在 v16.7.0 alpha 版本,且正在开放的RFC讨论。

Hooks是向后兼容的,这篇文档将向React开发者提供一个概览。

? State Hook

这是一个计数器的例子,点击按钮,数字加一。

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>
  );
}
复制代码

在这里,useState是一个Hook(我们稍后会讨论它是什么意思),我们在一个函数式组件中调用它来添加一些内部的状态。React 将在重新渲染间保留此状态,useState返回一个pair:包含了当前的状态值和一个可以用来更新该值的函数。你可以在一个事件监听器或者其他地方调用这个函数。它和Class中的setState是类似的,不过他没把新旧状态合并在一起。(稍后会有例子来比较在使用State Hooks时useState和this.state的差异)

useState只有一个参数作为他的初始状态,在上面的例子中,这个参数是0,因为计数器从0开始。请注意,和this.state不同的是,这里的state不一定非要是一个对象——你要是想那也行。初始状态只在首次渲染时使用。

声明多个状态变量

你可以在一个组件中多次使用State Hook

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

数组解构语法允许我们为通过调用useState声明的状态变量赋予不同的名称,这些名字并不是useState这个API的一部分,相反,React假定如果多次调用useState,就在每次渲染期间以相同的顺序执行。我们稍后会讨论这什么时候有用。

但到底什么是Hook呢?

Hooks 是一个React 函数组件内一类特殊的函数(通常以 "use" 开头,比如 "useState"),使开发者能够在 function component 里 ‘hook in’ state 和 life-cycles,以及使用 custom hook 复用业务逻辑。Hooks在Class组件中不能使用-这使得你可以在不写Class的情况下使用React(我们不建议您在一夜之间重写现有组件,但如果您愿意,可以开始在新组件中使用Hook。) React提供了一些像useState这样的内置Hook。你还可以创建custom Hook以在不同组件之间重用有状态行为。我们先来看看内置的Hooks。

⚡️ Effect Hook

你之前可能在React组件执行数据获取,订阅或手动更改DOM。我们称这种操作为“side effects”因为它们会影响其他的组件,并且不会在渲染期间就完成。

Effect Hook:useEffect为函数组件增添了执行side effects的能力。它与React Class中的componentDidMount,componentDidUpdate和componentWillUnmount具有相同的用途,但统一为单个API。 (我们将在使用Effect Hook时显示将useEffect与这些方法进行比较的示例。)

举个栗子,这个组件在React更新DOM之后设置文档标题

import { useState, useEffect } from 'react';
function Example() {
  const [count, setCount] = useState(0);
  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
复制代码

当你调用useEffect时,相当于告诉了React在刷新对DOM的更改后再运行你的“effect”函数。Effects是声明在Component内的,所以有权访问组件的props和state。默认情况下,React在每次render都会调用effects,包括第一次render。(我们将更多地讨论使用Effect Hook和class中的lifecycles进行比较。)

Effects还可以通过返回函数指定如何“清理”它们。例如,这个组件使用Effect来订阅朋友的在线状态,并通过取消订阅来清理:

import {useState,useEffect} from 'react'
function FriendStatus(props){
  const [isOnline,setIsOnline] = useState(null)
  function handleStatusChange(status){
    setIsOnline(status.isOnline)
  }
  useEffects(()=>{
      ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
        return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  })
  if(isOnline === null){
    return 'loading'
  }
   return isOnline ? 'Online' :'Offline'
}
复制代码

在这个例子中,React会在组件unmount时,以及在由于后续渲染而重新运行effects之前取消订阅ChatAPI(你也可以告诉React跳过重新订阅如果我们传给ChatAPI的props.friend.id没有变的话)

就像·useState·一样,你可以在一个Component中多次使用effect

function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }
  // ...
复制代码

Hooks允许您通过哪些部分相关(例如添加和删除订阅)来组织组件中的side effects,而不是基于生命周期方法强制拆分。 您可以在这个页面上了解有关useEffect的更多信息:Using the Effect Hook

✌️ Rules of Hooks

Hooks是JavaScript函数,但它们强加了两个额外的规则:

  • 只能在顶层调用Hooks。不要在循环,条件或嵌套函数中调用Hook。
  • 仅从React函数组件中调用Hooks。不要从常规JavaScript函数中调用Hook。 (还有另一个有效的地方叫Hooks - 你自己的定制Hooks。我们马上就会了解它们。)

我们提供了一个linter插件来自动执行这些规则。这些规则最初可能看起来有限或令人困惑,但它们对于使Hooks运行良好至关重要。

? Custom Hooks

有时,我们希望在组件之间重用一些有状态逻辑。以往,这个问题有两种流行的解决方案:HOC和render props。Custom Hook可以做到这些,并且让你不需往组件树添加更多的组件。 在前面,我们介绍了一个调用useState和useEffect Hooks的FriendStatus组件来订阅朋友的在线状态。假设我们还希望在另一个组件中重用此订阅逻辑: 首先,我们将这个逻辑提取到一个名为useFriendStatus的自定义Hook中:

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;
}
复制代码

它将friendID作为参数,并返回我们的朋友是否在线。 现在我们可以在组件中使用它:

function FriendStatus(props) {
 const isOnline = useFriendStatus(props.friend.id);

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

function FriendListItem(props) {
 const isOnline = useFriendStatus(props.friend.id);
 return (
   <li style={{ color: isOnline ? 'green' : 'black' }}>
     {props.friend.name}
   </li>
 );
}
复制代码

这些组件的状态是完全独立的。Hooks是重用有状态逻辑的一种方式,而不是状态本身。事实上,每次调用Hook都有一个完全隔离的state - 所以你甚至可以在一个组件中使用相同的自定义Hook两次。 Custom Hooks更像是一种约定而非功能,如果一个函数的名字以‘use’开头,把那个且他调用了其他的Hooks 我们称他为custom Hook 。useSomething命名约定也是linter插件在使用了hooks的代码中查找bug的原理。 您可以编写自定义Hook,涵盖各种用例,如表单处理,动画,声明性订阅,计时器,可能还有更多我们没有考虑过的。我们很高兴看到React社区提出的定制Hooks。

? Other Hooks

您可能会发现一些不太常用的内置Hook很有用。例如,useContext允许您订阅React上下文而不引入嵌套:

function Example() {
  const locale = useContext(LocaleContext);
  const theme = useContext(ThemeContext);
  // ...
}
复制代码

useReducer允许您使用reducer管理复杂组件的本地状态:

function Todos() {
  const [todos, dispatch] = useReducer(todosReducer);
  // ...
复制代码

这只是React 官网中关于Hooks的一篇大概的介绍,更加详细的使用文档,可以在官方文档中获得:HOOKS(Proposal)

转载于:https://juejin.im/post/5bd53d6a51882528382d8108

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值