内容简介:如果使用React的话,你可能就知道那些所谓的注意:hook刚刚发布,API可能会随时变化,建议查看https://react tjs.org/docs/hooks-intro.html的官方文档,并关注先看两个例子:
如果使用React的话,你可能就知道那些所谓的 hook 了。索菲·阿尔珀特和丹·阿布拉莫夫在今年的React大会上正式宣布了这一消息。他们的演讲视频可以在 这里 看到。我和许多人一样,对这个新特性很感兴趣。这篇文章基本上总结了我关于React hook的一点个人思考。
注意:hook刚刚发布,API可能会随时变化,建议查看https://react tjs.org/docs/hooks-intro.html的官方文档,并关注 RFC 。
hooks 是什么
先看两个例子:
import React, { useState } from 'react'; function Counter() { const initialValue = 0; const [ count, setCount ] = useState(initialValue); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
首先, hooks 适用于无状态组件。它们在用class定义的React组件中没有意义(事实上也不会起作用)。在上面的例子中, useState 是钩子。它的作用是使我们的Counter组件有状态。换句话说,我们拥有与使用class相同的组件状态功能。 useState 接受状态的初始值,并返回一个包含两个元素的数组。第一个是count,第二个是我们可以用来改变count的函数。
返回数组而不是对象的决定非常好。这样我们可以毫不费力地正确命名对象。
想象一下有如下一个钩子:
const { value: count, changeValue: setCount } = useState(initialValue);
看起来比想象的还要冗长。
到目前为止,定义为函数的React组件与定义为class的组件相比欠缺两样东西——管理组件状态和生命周期函数。 useState 用于管理组件状态,还有一个钩子叫做 useEffect ,它实际上是生命周期方法的替代者。
import React, { useEffect } from 'react'; function Example() { useEffect(() => { document.title = `The component is rendered`; return () => { document.title = `The component is removed from the DOM`; } }); return <p>Hello world</p>; }
当页面渲染完成后,执行传递给 useEffect 的函数,它类似于 componentDidMount 。当组件从页面中移除时,将调用我们在其中返回的函数,类似于 componentWillUnmount 。因为所有这些都是在函数内部定义的,我们可以访问props 和state。这意味着我们可以覆盖 componentDidUpdate 提供给我们的内容。
优势
如果我们使用钩子,编写的代码就会更少,代码可读性更好。我们只写函数,不写类。在构造函数中没有使用关键字this,也没有奇怪的绑定。React组件以声明式的方式编写,几乎没有分支,而且更容易跟踪。
class Counter extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; this.onButtonClicked = this.onButtonClicked.bind(this); } onButtonClicked() { this.setState({ count: this.state.count + 1 }); } render() { const { count } = this.state; return ( <div> <p>You clicked {count} times</p> <button onClick={this.onButtonClicked}> Click me </button> </div> ); } }
它与之前定义的Counter函数等价。里面有三个方法,所以我们需要看懂这些方法才能完全理解发生了什么。bind看起来很奇怪,但是我们必须这样做,由于性能原因,我们不能将.bind留在render方法中。总的来说,在使用class编写React组件时,我们必须写一些模板代码。我们采用钩子的写法重写Counter:
function Counter() { const initialValue = 0; const [ count, setCount ] = useState(initialValue); return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
用更少的代码实现同样的事情。
但对我来说更重要的是两件事——组件变得更容易阅读,状态逻辑更容易共享。
假设我想使用相同的Counter逻辑,但是使用不同的View。如果我们决定使用类,我们可能会使用函数作为子模式,就像这样:
class Counter extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; this.onButtonClicked = this.onButtonClicked.bind(this); } onButtonClicked() { this.setState({ count: this.state.count + 1 }); } render() { const { count } = this.state; const { children } = this.props; return children({ count, add: onButtonClicked }); } }
然后多次使用相同的计数器组件:
function AnotherCounter() { return ( <Counter> { ({ count, add }) => ( <div> <p>You clicked {count} times</p> <button onClick={add}> Click me </button> </div> ) } </Counter> ) }
现在我们在组件树中又多了一个div,随着代码变得复杂,早晚会遇到 嵌套层级过深 的问题。传递一个表达式作为children不是最自然的事情。另一方面,使用简单的JavaScript函数感觉很正常。
function useCounter(initialValue) { const [value, setCount] = useState(initialValue) return { value, increase: () => setCount(value + 1), } } export default function CounterA() { const counter = useCounter(0) return ( <div> <p>You clicked {counter.value} times</p> <button onClick={counter.increase}>Click me</button> </div> ) }
使用 hooks 可以将状态逻辑提取到一个简单的JavaScript函数中,该函数只是 useState 和 useEffect 等基本钩子的组合。
一些困惑
到目前为止,我们看到了 hooks 带来的好处。同时也会带来一些问题:
第一件事是编写React函数组件的思维方式。过去我们认为它们是简单、无状态的函数,只负责渲染内容。现在我们依然可以让它们这样,但是如果 hooks 变成了新的React组件开发方式,我们就不能继续说,如果它是一个函数,它没有状态,它纯粹是渲染的东西。特别是在使用 useEffect 钩子时,我们传递了一个函数,该函数可能会执行异步任务。这意味着,即使返回一个结果,定义为函数的React组件仍然是可变的。例如:
function FriendStatus(props) { const [isOnline, setIsOnline] = useState(null); useEffect(function onRender() { ChatAPI.subscribeToFriendStatus( props.friend.id, status => setIsOnline(status.isOnline) ); }); if (isOnline === null) { return 'Loading...'; } return isOnline ? 'Online' : 'Offline'; }
请注意 useEffect 接收一个在将来某个时刻执行的 onRender 函数。我们过去认为React组件会返回结果。我认为令人困惑的是 useEffect 处理的逻辑与React的渲染时机不同步。我的意思是,这不像我们拿到数据后显示数据。我们触发一个与呈现并行的过程。另外,我们也不希望在每次呈现 FriendStatus 时都触发 onRender 。有一个API可以处理这种情况——我们可以传递一个变量数组作为 useEffect 的第二个参数:
useEffect(function componentDidMount() { ChatAPI.subscribeToFriendStatus( props.friend.id, status => setIsOnline(status.isOnline) ); }, [numberOfFriends]);
当第一次看到 useState 的时候,这是我脑海中浮现的第一个问题“他们是如何做到的?”。当我看到Angular 2的依赖注入时,我也有同样的感觉。尽管Dan解释说,这个功能背后并没有真正的魔法,但它给人的感觉很神奇。
为了使 hooks 正常工作,我们必须遵循某些规则。例如,我们必须在函数顶部定义钩子,并避免将它们放在 if 语句或 for 循环中。
写到最后
正如我在文章开头说的,React中的 hooks 是实验性的,它们仍然是一个提案。你不应该用 hooks 重写你的应用,因为它们的API可能会改变。我认为这些 hooks 是朝着正确方向迈出的一步。然而,它们需要某种思维方式的转变才能被采用。这是因为它们不仅是一种模式,而且是一种新的范式,能够显著改变我们构建应用的方式。
hooks是一种新的组合方式和新的逻辑共享方式。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- Android开发 - 更"聪明"的申请权限方式
- 使用svn进行Web开发的最佳方式
- Node 后端开发的几种测试方式
- 用现代化的方式开发一个图片上传工具
- 用半励志的方式告诉你,怎么学习Python开发
- C# 开发 Windows 服务程序最简单的方式-Topshelf
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Perl语言编程
[美] Larry Wall、Tom Christiansen、Jon Orwant / 何伟平 / 中国电力出版社 / 2001-12 / 129.00元
这不仅仅是一本关于Perl的书籍,更是一本独一无二的开发者自己介绍该语言及其文化的书籍。Larry Wall是Perl的开发者,他就这种语言的未来发展方向提出了自己的看法。Tom Christiansen是最早的几个拥护者之一,也是少数几个在错综复杂的中游刃有余的人之一。Jon Orwant是《Perl Journal》的主编,该杂志把Perl社区组合成了一个共同的论坛,以进行Perl新的开发。一起来看看 《Perl语言编程》 这本书的介绍吧!