文章目录
1、为什么要使用Hooks
React Hooks是16.8版本引入的新特性,为了在不编写class的情况下使用state和其他的react特性。(说人话就是为了弥补函数式组件的缺陷,无法拥有和管理自己的状态以及生命周期等)。
函数式(组件)编程的好处:
- 更加倾向于JavaScript的心智模型(函数编程)
- 不需要创建实例,函数组件性能消耗小
缺点:没有自己的状态管理和生命周期。
class组件编程的好处:
- 可以在class组件内部定义自己的state,用来保存组件自己内部的状态
- 拥有自己的生命周期,可以在各个生命周期中编写相应的(事件或)逻辑。
缺点:一个最初的class组件,业务逻辑是相对较少较简单的;但随着业务需求的增加,组件内逻辑代码越来越多,但要拆分的时候就变得难以下手,如在componentDidmount发起一些网络请求和事件监听,(可能还需要在componentWillunmount移除)。很多代码逻辑往往混合在一起,如果强行拆分的话,可能会导致过度设计,增加代码的复杂度。class中还有新手难以理解的this指向。(增加学习成本)
2、上手Hooks
2.1 useState
import React from "react";
import { useState } from "react";
export default function App() {
const [message, setMessage] = useState("Hello");
const handleChangeMessage = () => {
setMessage("Hello React");
};
return (
<div>
<h2>内容:{message}</h2>
<button onClick={handleChangeMessage}>按钮</button>
</div>
);
}
2.1.1 基本用法
consy[xxx,setXxx] = useState(initialState)
useState是一个方法:接收一个任意类型的参数(可以是Number、Boolean、String、Object、Array类型等),返回一个变量和修改变量的函数的数组。可以使用数组解构接收值。
2.2 useEffect
在class组件生命周期中我们了解到,componentDidmount、componentDidupdate、componentWillunmount、render等生命周期。useEffect就允许我们在函数式组件中在某某时期做某某事情,如页面加载时进行网络请求和事件监听;在组件销毁时取消订阅。
useEffect又称为“副作用”。我们上面进行的各种操作就属于函数的副作用,因此可以在useEffect中进行“副作用”操作。
import React, { useState, useEffect } from "react";
export default function App() {
const [count, setCount] = useState(100);
useEffect(() => {
// 让标题随着state改变
document.title = count;
}, [count]);
return (
<div>
<h2>内容:{count}</h2>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
2.2.1 基本用法
useEffect(()=>{},[依赖项数组])
useState是一个方法:接收两个参数
第一个参数是 回调函数:()=> 返回值
第二个参数是 依赖项数组: [xxx,yyy,zzz]
2.2.2 执行时期
什么时候会执行effect中的副作用?(三种情况)
- 当useEffect没有依赖项数组的时候,第一次页面加载和每当state或props变化时导致页面重新渲染时,每次都会执行副作用(effect中的回调函数)
- 当useEffect的依赖项数组为空时 [ ],只有第一次页面加载时会执行副作用(仅执行一次)
- 当useEffect的依赖项数组有变量时 [xxx,yyy,zzz],第一次页面加载和每当依赖项数组中的其中一个依赖项变化时,就会执行副作用
2.2.3 清除工作
在useEffect的回调函数中,返回值可以又是一个回调函数,如
const [count, setCount] = useState(100);
useEffect(() => {
// 设置一个定时器,每过2秒打印一次hello
const time = setTimeout(() => {
console.log("hello");
}, 2000);
// 销毁定时器
return () => clearTimeout(time);
}, [count]);
useEffect回调函数返回的回调函数:
return () => {}
类似于componentWillUnmount生命时期。执行时期:组件被重新渲染(由自身渲染或父组件带动)或组件卸载的时候执行。
2.2.4 使用多个effect
使用useEffect中其中一个effect其主要是为了解决class生命周期中逻辑代码难以拆分问题:如网络请求、事件监听、手动修改DOM都是在componentDidmount中声明的,而useEffect允许我们编写多个effect,可以按照代码的用途分离它们。
React将按照effect声明的顺序依次调用组件中的每一个effect。
总结:比class的生命周期更加强大和方便。
2.3 useContext
useContext允许我们直接通过hooks获取context对象。通过上下文共享数据。
在这里提一个问题:为什么要使用hooks提供全局数据,而不是直接使用一个全局变量?
因为使用useContext的目的是能够进行数据的绑定。我们在组件树的根组件提供一个Provider属性,以便子组件能够获取到数据,获取数据的同时,如果数据发生了变化,那么子组件就会拿着新变化的数据重新渲染。一个普通的全局变量则做不到这一点。
2.3.1 基本用法
创建:createContext()
import React from 'react'
import { createContext } from "react";
export const UserContext = createContext();
export const ThemeContext = createContext();
提供订阅:xxxContext.Provider
<UserContext.Provider value={xxx}>
<ThemeContext.Provider value={yyy}>
<App />
</ThemeContext.Provider>
</UserContext.Provider>
消费:直接通过hooks而不需要customer
const user = useContext(UserContext);
const theme = useContext(ThemeContext);
return (
<div>
{user.xxx}
{theme.yyy}
</div>
2.4 useReducer(略过)
useReducer是useState的一个变种,用于管理复杂数据,但实际开发中使用这个hook极少。暂且跳过。