内容简介:本文为意译,翻译过程中掺杂本人的理解,如有误导,请放弃继续阅读。原文地址:Hooks at a GlanceHooks是即将到来的React特性。这个特性能让你不需要编写class component的前提下也能使用state和其他React特性。当前,在React v16.7.0-alpha版本中,它们是可用的。
本文为意译,翻译过程中掺杂本人的理解,如有误导,请放弃继续阅读。
原文地址:Hooks at a Glance
正文
Hooks是即将到来的React特性。这个特性能让你不需要编写class component的前提下也能使用state和其他React特性。当前,在React v16.7.0-alpha版本中,它们是可用的。
Hooks是React中一个向后兼容的特性。这篇文档将会为React老手们提供一个Hooks特性的概览。
一. 什么是Hook?
Hooks是一个函数。它能像钩子一样,让你能在函数组件的内部也能“勾住”React state,生命周期函数等React特性。Hooks不能在类(classes)里面使用,它能让你在不使用类的前提下来使用React。注意,我们并没有推荐你马上就重写现有的组件。但是如果你想的话,你可以在一些新组件上试用一下。
React提供了一些内置的Hook-比如useState。你也可以创建一些自己的Hook来在组件间复用一些状态型的逻辑和行为。首先,我们来看看那些内置的Hook。
二. React Hook特性都包含啥?
1.State Hook
以下示例代码渲染的是counter组件。当你点击按钮的时候,当前的count值就增加。
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。我们在一个function component里面调用了它来为这个组件添加了一个local state。React负责在重复渲染过程中保存这个local state。useState返回了一对值:当前state值和一个负责更新这个state的函数。你可以在event handler或者别的地方来调用这个函数。它相当于class component中的this.setState。不同的是,Hook返回的这个函数并不会合并新老state。关于这两者(useState所返回的函数和this.state)的比较,我们会在这个章节进行说明。
useState的唯一参数就是state的初始值。在上面的例子中,这个初始值就是0。因为我们的counter是从0开始的。注意,不像this.state,这里的state的初始值并不要求一定是一个对象。不过,如果你喜欢的话,对象也是可以的。Hook的初始state值只会在第一次渲染的时候用到。
除了上述提到的,用Hook生成的state不一定是一个对象外。Hook的state跟class component的state的还有一个不同点就是:Hook state可以有多个。也就是说,你可以在一个function component中使用多次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所返回的state变量进行命名。这个命名并不是useState这个API语法的一部分,所以,叫什么都不重要。React在这里做了一个假设。什么假设呢?那就假设你在每一渲染过程中所调用的useState的顺序是一样的。我们稍后再来讨论为什么要这么做。
2.Effect Hook
你以前一定在React组件里面做过数据获取,事件订阅或者DOM操作等行为。我们把这些行为称之为“副作用(side effects)”。那是因为这些行为会影响到其他的组件,并且不能发生在render期间的。
effect hook - useEffect,为function component添加了执行副作用的能力。这在hook特性加入到React之前是办不到的。useEffect这个hook起到的作用跟class component中的componentDidMount,componentDidUpdate和componentWillUnmount等生命周期函数的作用是一样的。不同的是,useEffect将这三个方法合成到一个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,你想在[将对virtual DOM的更新映射到真实DOM]之后执行你的副作用。副作用声明在组件的内部,这样一来,副作用就能访问组件的props和state了。默认情况下,React会在每次渲染之后都会执行你的副作用,这里面包括了第一次渲染。
副作用也可以可选地通过返回一个函数来告知React如何去清除(clean up)这些副作用。举个例子,下面这个组件使用了一个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); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; }); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline'; } 复制代码
在这里例子中,React将会在组件卸载的时候取消对ChatAPI的订阅。在每次重新渲染之前也是一样的,也会取消对ChatAPI的订阅。如果你不想每次渲染之前后都这样,你也可以告诉React跳过某些订阅。只有props.friend.id变了才重新去订阅。至于如何告诉React跳过某些订阅呢,请查看这里。
跟useState一样,你也可以在一个组件的内部多次调用useEffect:
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可以让在组件内部根据哪块代码是相关联的来组织代码(比如说,订阅和取消订阅的代码就是想关联的),而不是像以前那样简单粗暴地逼你只能基于生命周期方法来作代码的分离。
3.其他内置的Hooks
除了,useState和useEffect这两个比较常用的Hook之外,React还提供了一些比较少用但是却很有用的Hook来给大家。比如,useContext就是其中一个。它能让你在不引入额外的组件树层级的情况下订阅到React context:
function Example() { const locale = useContext(LocaleContext); const theme = useContext(ThemeContext); // ... } 复制代码
再比如useReducer这个Hook。它能让你用一个reducer去管理组件复杂的本地state:
function Todos() { const [todos, dispatch] = useReducer(todosReducer); // ... 复制代码
以上只是抛砖引玉,更多内置的Hook API以及其使用细节请到Hooks API Reference里面查阅。
4.打造你自己的Hooks
有时候,我们想在组件间复用一些状态型逻辑。传统(Hooks没出来前)的做法是使用高阶组件和render props两种技术来实现对这行状态型逻辑的封装。现在Hook来了。它能让你在不引入额外的组件树层级的前提下达成同样的目标。
在这篇文档的前面部分,我们介绍了一个叫FriendStatus的组件。这个组件的内部通过调用useState和useEffect这两个Hook来实现了对朋友在线状态的订阅。假如我们想在别的组件复用这段订阅逻辑代码,那我们该怎么办呢?
首先,我们应该提取这段逻辑到一个custom Hook里面。我们给这个custom Hook命名为useFriendStatus:
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; } 复制代码
这个custom Hook接收friendID作为它的参数,最后返回一个boolean值来标识该用户是否在线。
然后,我们就可以像使用 built in Hook一样使用它了:
// 在A组件我们是这样用 function FriendStatus(props) { const isOnline = useFriendStatus(props.friend.id); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline'; } // 在B组件我们又是这样用 function FriendListItem(props) { const isOnline = useFriendStatus(props.friend.id); return ( <li style={{ color: isOnline ? 'green' : 'black' }}> {props.friend.name} </li> ); } 复制代码
以上两个组件的state是完全独立的。 准确地来说,Hooks是关于复用状态型逻辑(stateful logic)而不是复用状态(state)本身的一种方案 。实际上,每一次调用Hook所生成的state是完全独立的。所以你完全可以在一个组件内部调用两次custom Hook来生成两个不同的state。
你可以编写自己的custom Hook来覆盖许多常见的业务场景。比如说,表单处理,动画,声明式的订阅,定时器等等。此外,还有很多场景我们没想得到的,你自己也可以想想如何使用custom Hook来完成封装。我们很期待React社区将会推出什么样的custom Hooks!
关于custom Hooks的更多内容,请查看 Building Your Own Hooks 。
5.Hooks的铁规
Hooks只是一些javascript函数而已。但是不同于普通的javascript函数,React为Hooks强加了两条额外的规则:
- 只能在当前作用域的顶层来调用Hooks。不能在循环语句,条件分支语句或者被嵌套函数里面来调用Hooks。
- 只能在React的function component中调用Hooks。不要在普通的javascript函数里面调用Hooks。注意,还有另外一个地方可以调用Hooks。那就是custom Hooks。在custom Hooks中调用Hooks也要遵循第一条规则。
我们提供了一个linter plugin来自动地检查用户的Hooks的调用是否符合这两条规则。我们也知道,这两条规则看起来有点限制过头或者令人困惑的。但是没办法啊,这两条规则是保证Hooks有效发挥作用的必要前提条件。
你可以在Rules of Hooks专栏里面查阅更多的细节。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。