初识React Hooks
为什么需要Hook?
Hook 是 React 16.8 的新增特性,它可以让我们在不编写class的情况下使用state以及其他的React特性(比如生命周期)。
class组件相对于函数式组件有什么优势?
class组件可以定义自己的state,用来保存组件自己内部的状态;
- 函数式组件不可以,因为函数每次调用都会产生新的临时变量;
class组件有自己的生命周期,我们可以在对应的生命周期中完成自己的逻辑;
- 比如在componentDidMount中发送网络请求,并且该生命周期函数只会执行一次;
- 函数式组件在学习hooks之前,如果在函数中发送网络请求,意味着每次重新渲染都会重新发送一次网络请求;
class组件可以在状态改变时只会重新执行render函数以及我们希望重新调用的生命周期函数componentDidUpdate等;
- 函数式组件在重新渲染时,整个函数都会被执行,似乎没有什么地方可以只让它们调用一次;
所以,在Hook出现之前,对于上面这些情况我们通常都会编写class组件
Class组件存在的问题
- 复杂组件变得难以理解:
- 我们在最初编写一个class组件时,往往逻辑比较简单,并不会非常复杂。但是随着业务的增多,我们的class组件会变得越来越复杂;
- 比如componentDidMount中,可能就会包含大量的逻辑代码:包括网络请求、一些事件的监听(还需要在componentWillUnmount中移除);
- 而对于这样的class实际上非常难以拆分:因为它们的逻辑往往混在一起,强行拆分反而会造成过度设计,增加代码的复杂度;
Class组件和使用Hooks的函数式组件简单对比
类式组件
函数式组件:
简洁程度可想而知。
小提示:Hook指的类似于useState、useEffect这样的函数;Hooks是对这类函数的统称;
useState
useState会帮助我们定义一个 state变量,useState 是一种新方法,它与 class 里面的 this.state 提供的功能完全相同。
- ✓ 一般来说,在函数退出后变量就会”消失”,而 state 中的变量会被 React 保留。
useState接受唯一一个参数,在第一次组件被调用时使用来作为初始化值。(如果没有传递参数,那么初始化值为undefined)。
useState的返回值是一个数组,我们可以通过数组的解构,来完成赋值会非常方便。
当然,我们也可以在一个组件中定义多个变量和复杂变量(数组、对象)
小提示:为什么叫 useState 而不叫 createState?
“create” 可能不是很准确,因为 state 只在组件首次渲染的时候被创建。
在下一次重新渲染时,useState 返回给我们当前的 state。
如果每次都创建新的变量,它就不是 “state”了。
这也是 Hook 的名字总是以 use 开头的一个原因
1 | import React, { memo, useState } from 'react' |
useEffect
通过useEffect的Hook,可以告诉React需要在渲染后执行某些操作;
useEffect要求我们传入一个回调函数,在React执行完更新DOM操作之后,就会回调这个函数;
默认情况下,无论是第一次渲染之后,还是每次更新之后,都会执行这个回调函数;
useEffect的清除机制
useEffect传入的回调函数A本身可以有一个返回值,这个返回值是另外一个回调函数B:
1 | type EffectCallback = () => (void | (() => void | undefined)); |
为什么要在effect 中返回一个函数?
这是effect 可选的清除机制。每个effect 都可以返回一个清除函数;
如此可以将添加和移除订阅的逻辑放在一起;
它们都属于effect 的一部分;
1 | import React, { memo, useEffect } from 'react' |
使用多个Effect
使用Hook的其中一个目的就是解决class中生命周期经常将很多的逻辑放在一起的问题:比如网络请求、事件监听、手动修改DOM,这些往往都会放在componentDidMount中;
Hook 允许我们按照代码的用途分离它们,而不是像生命周期函数那样:React 将按照effect 声明的顺序依次调用组件中的每一个effect;
使用Effect Hook,我们可以将它们分离到不同的useEffect中:
1 | import React, { memo, useEffect } from 'react' |
useEffect性能优化
默认情况下,useEffect的回调函数会在每次渲染时都重新执行,但是这会导致两个问题:
某些代码我们只是希望执行一次即可,类似于componentDidMount和componentWillUnmount中完成的事情;(比如网
络请求、订阅和取消订阅); 另外,多次执行也会导致一定的性能问题;
我们如何决定useEffect在什么时候应该执行和什么时候不应该执行呢?
useEffect实际上有两个参数:
参数一:执行的回调函数;
参数二:该useEffect在哪些state发生变化时,才重新执行;(受谁的影响)
但是,如果一个函数我们不希望依赖任何的内容时,也可以传入一个空的数组 []:
那么这里的两个回调函数分别对应的就是componentDidMount和componentWillUnmount生命周期函数了;
1 | import React, { memo, useEffect } from 'react' |
useContext
Context Hook允许我们通过Hook来直接获取某个Context的值;
注意事项:
当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重新渲染,并使用最新传递给 MyContext provider 的
context value 值。
index.js
1 | const root = ReactDOM.createRoot(document.getElementById('root')); |
context/index.js
1 | import { createContext } from "react"; |
App.js
1 | import React, { memo, useContext } from 'react' |
Use this card to join the candyhome and participate in a pleasant discussion together .
Welcome to aqing's candyhome,wish you a nice day .