在本文结束时,您将可以回答如下问题:react
Hooks 能够作到如下事情:json
若是你已经使用过React,你就会知道复杂多变,有状态的逻辑是如何获得的,当应用程序为功能添加了几个新功能时,就会发生组件代码变得复杂而难以维护这种状况。为了尝试简化这个问题,React背后的大脑试图找到解决这个问题的方法。数组
(1) 在组件之间重用有状态逻辑架构
hooks容许开发人员编写简单,有状态的功能组件,并在开发时花费更少的时间来设计和重构组件层次结构。怎么样?使用钩子,您能够在组件之间_获取_和_分享_有状态逻辑。框架
(2) 简化组件逻辑函数
当您的应用程序中出现不可避免的指数级逻辑增加时,简单的组件就回由于各类状态逻辑和生命周期等等因素,而变得繁琐和复杂。组件的职责增加并变得不可分割。反过来,这使编码变得麻烦而且测试困难。工具
class是React架构的重要组成部分。class有许多好处,但它们为初学者创造了入门的障碍。对于class,您还必须记住将this绑定到事件处理程序,所以代码可能变得冗长且有点多余。post
React版本 16.8.学习
import { useState, useEffect } from 'react';
很简单,但你如何实际使用这些新方法?如下示例很是简单,但这些方法的功能很是强大。测试
使用状态钩子(state hook)的最好方法是对其进行解构并设置原始值。第一个参数将用于存储状态,第二个参数用于更新状态。
例如:
const [weight, setWeight] = useState(150); onClick={() => setWeight(weight + 15)}
weight是状态
setWeight是一种用于更新状态的方法
useState(150)是用于设置初始值(任何基本类型)的方法
值得注意的是,您能够在单个组件中屡次构造状态hook:
const [age, setAge] = useState(42); const [month, setMonth] = useState('February'); const [todos, setTodos] = useState([{ text: 'Eat pie' }]);
所以,该组件可能看起来像:
import React, { useState } from 'react'; export default function App() { const [weight, setWeight] = useState(150); const [age] = useState(42); const [month] = useState('February'); const [todos] = useState([{ text: 'Eat pie' }]); return ( Current Weight: {weight} Age: {age} Month: {month} setWeight(weight + 15)}> {todos[0].text} ); }
使用effect hook 就好像使用componentDidMount, componentDidUpdate, 和 componentWillUnmount这类的生命周期的方法。
例如:
// similar to the componentDidMount and componentDidUpdate methods useEffect(() => { document.title = You clicked ${count} times; });
组件更新的任什么时候候,渲染后都会调用useEffect。如今,若是你只想在变量count改变时更新useEffect,你只需将该事实添加到数组中方法的末尾,相似于高阶reduce方法末尾的累加器。
// check out the variable count in the array at the end... useEffect(() => { document.title = You clicked ${count} times; }, [ count ]);
让咱们结合两个例子:
const [weight, setWeight] = useState(150); useEffect(() => { document.title = You weigh ${weight}, you ok with that?; }, [ weight ]); onClick={() => setWeight(weight + 15)}
所以,当触发onClick时,也会调用useEffect方法,并在DOM更新后在文档标题中呈现新的数据。
例:
import React, { useState, useEffect } from 'react'; export default function App() { const [weight, setWeight] = useState(150); const [age] = useState(42); const [month] = useState('February'); const [todos] = useState([{ text: 'Eat pie' }]); useEffect(() => { document.title = You weigh ${weight}, you ok with that?; }); return ( Current Weight: {weight} Age: {age} Month: {month} setWeight(weight + 15)}> {todos[0].text} ); }
useEffect很是适合进行API调用:
useEffect(() => { fetch('https://jsonplaceholder.typicode.com/todos/1') .then(results => results.json()) .then((data) => { setTodos([{ text: data.title }]); }); }, []);
React钩子看起来很棒,可是若是你花一点时间,你可能会意识到在多个组件中从新初始化多个钩子方法,好比useState和useEffect,可能会违背DRY(Don't repeat yourself)原则。那么,让咱们看看如何经过建立自定义钩子来重用这些新内置方法。
是的,React钩子有规则。这些规则乍一看彷佛是很是规的,可是一旦你理解了React钩子如何启动的基础知识,规则就很容易理解。
(1) 必须在顶层以相同的顺序调用挂钩。(依次调用)
Hooks建立一个钩子调用数组来保持秩序。这个命令有助于React告诉区别,例如,在单个组件中或跨应用程序的多个useState和useEffect方法调用之间。
例如:
// This is good! function ComponentWithHooks() { // top-level! const [age, setAge] = useState(42); const [month, setMonth] = useState('February'); const [todos, setTodos] = useState([{ text: 'Eat pie' }]); return ( //... ) }
在第一次渲染时,42,February,[{text:'Eat pie'}]都被推入状态数组。
当组件从新渲染时,忽略useState方法参数。
age,month和todos的值是从组件的状态中检索的,这是前面提到的状态数组。
(2) 没法在条件语句或循环中调用挂钩。
因为启动hooks的方式,不容许使用within条件语句或循环。对于hooks,若是在从新渲染期间初始化的顺序发生变化,则极可能您的应用程序没法正常运行。您仍然能够在组件中使用条件语句和循环,但不能在代码块内使用钩子。
例如:
// DON'T DO THIS!! const [DNAMatch, setDNAMatch] = useState(false) if (name) { setDNAMatch(true) const [name, setName] = useState(name) useEffect(function persistFamily() { localStorage.setItem('dad', name); }, []); } // DO THIS!! const [DNAMatch, setDNAMatch] = useState(false) const [name, setName] = useState(null) useEffect(() => { if (name) { setDNAMatch(true) setName(name) localStorage.setItem('dad', name); } }, []);
(3) 钩子不能用在class组件中。
钩子必须在功能组件或自定义钩子函数中初始化。自定义钩子函数只能在功能组件中调用,而且必须遵循与非自定义钩子相同的规则。
您仍然能够在同一个应用程序中使用类组件。您可使用hooks做为类组件的子项呈现功能组件。
(4) 自定义钩子应该以单词use开头而且是驼峰式的。
这是一个强有力的建议而非规则,但它将有助于您的应用程序的一致性。你也会知道,当你看到一个以“use”为前缀的函数时,它多是一个自定义钩子。
自定义挂钩只是遵循与非自定义挂钩相同规则的函数。它们容许您整合逻辑,共享数据以及跨组件重用钩子。
当您须要在组件之间共享逻辑时,最好使用自定义挂钩。在JavaScript中,当您想要在两个单独的函数之间共享逻辑时,您能够建立另外一个函数来支持它。好吧,就像组件同样,hooks也是function。您能够提取hooks逻辑,以便在应用程序的组件之间共享。在编写自定义hooks时,您能够命名它们(再次以“use”开头),设置参数,并告诉它们应该返回什么(若是有的话)。
例如:
import { useEffect, useState } from 'react'; const useFetch = ({ url, defaultData = null }) => { const [data, setData] = useState(defaultData); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); useEffect(() => { fetch(url) .then(res => res.json()) .then((res) => { setData(res); setLoading(false); }) .catch((err) => { setError(err); setLoading(false); }); }, []); const fetchResults = { data, loading, error, }; return fetchResults; }; export default useFetch;
Hooks容许您在应用程序增加时抑制复杂性,并编写更易于理解的代码。下面的代码是两个具备相同功能的组件的比较。在第一次比较以后,咱们将在伴随容器的组件中使用自定义钩子展现更多好处。
如下类组件应该看起来:
import React from 'react'; class OneChanceButton extends React.Component { constructor(props) { super(props); this.state = { clicked: false, }; this.handleClick = this.handleClick.bind(this); } handleClick() { return this.setState({ clicked: true }); } render() { return ( You Have One Chance to Click ); } } export default OneChanceButton;
如何使用钩子实现相同的功能来简化代码并提升可读性:
import React, { useState } from 'react'; function OneChanceButton(props) { const [clicked, setClicked] = useState(false); function doClick() { return setClicked(true); } return ( You Have One Chance to Click ); } export default OneChanceButton;
React hooks是一个惊人的新功能!实施的理由是合理的;而且,再加上这一点,我相信这将极大地下降React编码的门槛,并使其保持在最喜欢的框架之上列表。看到这会如何改变第三方库的工做方式,尤为是状态管理工具和路由器,将会很是使人兴奋。
总之,React钩子:
推荐阅读: https://juejin.im/post/5be8d3...