Hooks are a new addition in React 16.8. They let you use state and other React features without writing a class.
楼主最近在整理 React Hooks
的一些资料,为项目重构做准备,下午整理成了这篇文章。
若是以前没接触过相关概念,那么经过这篇文章, 你将会了什么是React Hooks
, 它是作什么的
, 以及如何使用
。html
下面我会用一个具体的例子来讲明, 经过这个例子, 你将了解:react
React Hooks
React Class components
实现一样的逻辑先快速搭建一个项目:es6
npx create-react-app exploring-hooks
import React, { Component } from "react"; export default class Button extends Component { state = { buttonText: "Click me, please" }; handleClick = () => { this.setState(() => { return { buttonText: "Thanks, been clicked!" }; }); }; render() { const { buttonText } = this.state; return <button onClick={this.handleClick}>{buttonText}</button>; } }
功能很是简单: 点一下按钮, 就更新 button 的 text。编程
这里,咱们将再也不使用 setState 和 ES6 Class. 轮到咱们的Hooks
登场了:json
import React, { useState } from "react";
引入 useState
就意味着咱们将要把一些状态管理置于组件内部, 并且咱们的 React Component
将再也不是一个 ES6 class
, 取而代之的是一个简单的纯函数
。segmentfault
引入 useState
以后,咱们将从中取出一个含有两个元素的数组:api
const [buttonText, setButtonText] = useState("Click me, please");
若是对这个语法有疑问, 能够参考 ES6 解构.数组
这两个值的名字, 你能够随意取, 和 React 无关,可是仍是建议你根据使用的目的取一个足够具体和清晰的名字
。app
就好比上面写的, 一个表明是 buttonText 的 值
, 另外一个表明是 setButtonText 的 更新函数
。less
给 useState
传入的是一个初始值
, 好比, 这个按钮的最初要显示的是: Click me, please。
这个简单的例子的代码全貌:
import React, { useState } from "react"; export default function Button() { const [buttonText, setButtonText] = useState("Click me, please"); function handleButtonClick() { return setButtonText("Thanks, been clicked!"); } return <button onClick={handleButtonClick}>{buttonText}</button>; }
下面咱们将介绍如何使用 Hooks 获取数据。
在这以前, 咱们都是在 componentDidMount
函数里调API:
import React, { Component } from "react"; export default class DataLoader extends Component { state = { data: [] }; async componentDidMount() { try { const response = await fetch(`https://api.coinmarketcap.com/v1/ticker/?limit=10`); if (!response.ok) { throw Error(response.statusText); } const json = await response.json(); this.setState({ data: json }); } catch (error) { console.log(error); } } render() { return ( <div> <ul> {this.state.data.map(el => ( <li key={el.id}>{el.name}</li> ))} </ul> </div> ); } }
这种代码你们想必都很是熟悉了, 下面咱们用 Hooks 来重写:
import React, { useState, useEffect } from "react"; export default function DataLoader() { const [data, setData] = useState([]); useEffect(() => { fetch("http://localhost:3001/links/") .then(response => response.json()) .then(data => setData(data)); }); return ( <div> <ul> {data.map(el => ( <li key={el.id}>{el.title}</li> ))} </ul> </div> ); }
运行一下就会发现,哎呦, 报错了, 无限循环:
缘由其实也很是简单, useEffect
存在的目的 和componentDidMount, componentDidUpdate, and componentWillUnmount
是一致的, 每次state 变化 或者 有新的props 进来的时候,componentDidUpdate componentDidUpdate` 都会执行。
要解决这个 "bug" 也很是简单, 给 useEffect 传入一个空数组做为第二个参数:
useEffect(() => { fetch("http://localhost:3001/links/") .then(response => response.json()) .then(data => setData(data)); },[]); // << super important array
关于 Hook 的详细信息能够参考: Using the Effect Hook
看到这你可能会按捺不住心里的小火苗,要去重构项目,我的还不建议这么作,由于接下来的几个版本中可能会有变化, 就像Ryan Florence 建议的:
Hooks are not the endgame for React data loading.Data loading is probably the most common effect in an app.
Don't be in a big hurry to migrate to hooks for data unless you're okay migrating again when suspense for data is stable.
Own your churn.
不管怎么说, useEffect 的出现仍是一件好事。
能显然是能的, 不过没什么意义, 好比把上面的代码改一下:
import React, { useState, useEffect } from "react"; export default function DataLoader(props) { const [data, setData] = useState([]); useEffect(() => { fetch("http://localhost:3001/links/") .then(response => response.json()) .then(data => setData(data)); }, []); return props.render(data) }
从外部传入一个render便可, 可是这样作毫无心义: Reack Hooks 自己就是为了解决组件间逻辑公用的问题的。
仍是上面的例子,咱们把取数据的逻辑抽出来:
// useFetch.tsx import { useState, useEffect } from "react"; export default function useFetch(url) { const [data, setData] = useState([]); useEffect(() => { fetch(url) .then(response => response.json()) .then(data => setData(data)); }, [] ); return data; }
在其余组件中引用:
import React from "react"; import useFetch from "./useFetch"; export default function DataLoader(props) { const data = useFetch("http://localhost:3001/links/"); return ( <div> <ul> {data.map(el => ( <li key={el.id}>{el.title}</li> ))} </ul> </div> ); }
上面咱们说到 Reack Hooks 自己就是为了解决组件间逻辑公用的问题的。
回顾咱们如今的作法,几乎都是面向生命周期编程:
Hooks 的出现是把这种面向生命周期编程变成了面向业务逻辑编程,让咱们不用再去关注生命周期:
并且, 最新的React 中, 预置了大量的Hooks, 最重要两个的就是: useState
and useEffect
.
useState 使咱们在不借助 ES6 class 的前提下, 在组件内部使用 state 成为可能
。
useEffect 取代了 componentDidMount, componentDidUpdate, and componentWillUnmount
, 提供了一个统一的API
。
除了这两个以外, 能够在官方文档中了解更多:
一个显而易见的事实是, 过不来了多久, 咱们就会有三种建立React components 的姿式:
做为一个 React 忠实粉丝, 看到这些积极的变化实在是使人感到愉悦。
还有不少帮助咱们更好的学和掌握 React Hooks, 也在这里分享一下:
首先仍是官方文档: Introducing Hooks, Hooks at a Glance 是稍微深刻一些的内容。
而后是一个入门教程: Build a CRUD App in React with Hooks.
关于状态管理, 还有一个比较有趣的文章: useReducer, don't useState
比较有意思的是, 咱们最后会大量使用 useReducer, 形势和 Redux 很是相似:
function reducer(state, action) { const { past, future, present } = state switch (action.type) { case 'UNDO': const previous = past[past.length - 1] const newPast = past.slice(0, past.length - 1) return { past: newPast, present: previous, future: [present, ...future], } case 'REDO': const next = future[0] const newFuture = future.slice(1) return { past: [...past, present], present: next, future: newFuture, } default: return state } }
这也从侧面证实了Redux 在社区中的影响力( 其实这两个东西的核心开发者是同一我的 )。
大概就是这些, 但愿能对你们有些启发和帮助。
才疏学浅,行文如有纰漏,还请各位大大帮忙指正, 谢谢。