开发中常用的Hook


开发中常用的Hook

什么是Hook?

Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数,用来实现一些 class 组件的特性的。

 1  // 引入 React 中的 useState Hook。它让我们在函数组件中存储内部 state。
 2  import React, { useState } from 'react';
 3  ?
 4  function Example() {
 5  // 声明一个叫 “count” 的 state 变量。
 6  //useState 就是一个 Hook 
 7  //当前状态和一个让你更新它的函数
 8  //useState( ) 括号里面是count 的初始值
 9  const [count, setCount] = useState(0);
10  return (
11   
12

You clicked {count} times

13 16
17 ); 18 }

Hook 不能在 class 组件中使用

class 组件比较重量级 -- 开发和维护有一定的难度,后来使用 函数组件,比较轻量,但是没有 calss的特性(state),需要使用一些别的方式来弥补 --> Hooks  

【官网相关链接】

EffectHook(副作用Hook)

副作用 hook 用来处理一些React之外的事件,比如ajax请求

但是其实 EffectHook 最常见的使用场景是 模拟 生命周期

用法:当useEffect依赖的数据发生变化,就会调用回调函数

useEffect(回调函数, [依赖的数据]);

格式 : 

useEffect(当依赖发生变化时调用的函数, [依赖的数据]);
 1  //需求:监视count
 2  //引入副作用钩子函数
 3  import React, { useEffect } from "react";
 4  ?
 5  export default function EffectHook() {
 6      
 7    const [count, setCount] = useState(0);
 8      
 9    //count作为EffectHook的依赖,所以只要count发生了变化,就会触发这个回调的调用。
10    useEffect(() => {
11      console.log("EffectHook调用了");
12    },[count]);
13      
14    const onClick = () => {
15      setCount(count + 1);
16    };
17      
18    return (
19      
20

Count:{count}

21

Double:{double}

22 23
24 ); 25 }
使用EffectHook模拟生命周期:
a.模拟componentDidMount
 useEffect(() => {
     console.log("这是用来模拟挂载期的");
 }, []);
b.模拟componentDidUpdate
 useEffect(() => {
     console.log("这是用来模拟更新期的");
 }, [deps]);
c.模拟componentWillUnmount
 useEffect(() => {
     return ()=>{
         // 在这里面写卸载期的代码
         console.log("这是用来模拟卸载期的");
     }
 }, []);

注意:

同个useEffect下,在检测销毁和检测字段更新之间,只能二选一。留下空数组,可以检测到return中的销毁。数组非空时,视图更新会带动return返回值,因此如果要检测字段更新,就无法检测销毁。

StateHook

这是一个react提供好的用于实现state响应式特性的hook,使用如下:

 1  export default function StateHook() {
 2    // 调用useState得到一个数组,顺便解构出来两个东西,一个是数据,一个是用于操作数据的函数
 3    const [count, setCount] = useState(0);
 4    const onClick = () => {
 5      // 调用对应的方法操作数据
 6      setCount(count + 1);
 7    };
 8    return (
 9      
10 {/* 直接渲染对应的数据 */} 11

Count:{count}

12 13
14 ); 15 }

值得注意的是,hook只能使用在函数的最外层,任何别的位置都会报错。

声明多个 state 变量

你可以在一个组件中多次使用 State Hook

1  function ExampleWithManyStates() {
2    // 声明多个 state 变量!
3    const [age, setAge] = useState(42);
4    const [fruit, setFruit] = useState('banana');
5    const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
6    // ...
7  }

自定义Hook

使用hook可以让我们的数据的操作数据的逻辑放在一起,并且可以实现封装,把代码整理地更加易于维护。

如果在操作数据的过程中有一些比较复杂的逻辑,我们就可以采用自定义hook的方式把这部分逻辑分离出来。

 1  export default function StateHook() {
 2    const [count, setCount] = useState(0);
 3    const onClick = () => {
 4      // 如果有更加复杂的逻辑(假装很复杂)
 5      let val = 0;
 6      if (count > 0) {
 7        val = count - 1;
 8      } else {
 9        val = count + Math.floor(Math.random() * 10);
10      }
11      setCount(val);
12    };
13    return (
14      
15

Count:{count}

16 17
18 ); 19 }

如果我们在页面里面有大量的复杂逻辑,这样同样会使代码变得非常杂乱,后期难以维护,于是我们可以这样写。

 1  // 自定义hook要求以use开头
 2  function useCount(initValue = 0) {
 3    const [count, setCount] = useState(initValue);
 4    const fn = () => {
 5      let val = 0;
 6      if (count > 0) {
 7        val = count - 1;
 8      } else {
 9        val = count + Math.floor(Math.random() * 10);
10      }
11      setCount(val);
12    };
13    return [count, fn];
14  }
15  export default function StateHook() {
16    // 调用我们自定义的hook , 把复杂的逻辑全抽离到自定义hook,这样在我们的组件里面就尽可能简洁了
17    const [count, setCount] = useCount();
18    const onClick = () => {
19      setCount();
20    };
21    return (
22      
23

Count:{count}

24 25
26 ); 27 }

ContextHook

使用 useContext 使用context 进行多级组件传递数据

用法:

  1. createContext

  1. Provider

  1. useContext

const Provider给的value = useContext(在第1步创建的context);

ContextHook基本使用步骤如下:

a.调用createContext创建一个Context对象
 const MyContext = createContext();
b.使用Provider组件提供一个“全局”数据
 1  export default function ContextHook() {
 2    const [count, setCount] = useState(10);
 3    const add = (val) => {
 4      setCount(count + val);
 5    };
 6    return (
 7      
 8        
 9      
10    );
11  }
c.在后代组件里面使用useContext方法获取Context对象
 1  function Parent() {
 2    return (
 3      
4 5
6 ); 7 } 8 function Child() { 9 const context = useContext(MyContext); 10 return ( 11
12 {/* context对象就是之前的Provider里面的value属性 */} 13

count from ancestors:{context.count}

14 15
16 ); 17 } 18 import React, { createContext, useContext, useState } from "react"; 19 // 1. 创建一个context 20 const MyContext = createContext(); 21 ? 22 export default function ContextStudy() { 23 const [count, setCount] = useState(5); 24 const add = () => { 25 setCount(count + 1); 26 }; 27 // 2. 需要一个Provider 28 return ( 29 30 31 32 ); 33 } 34 ? 35 function Parent() { 36 return ; 37 } 38 ? 39 function Child() { 40 const data = useContext(MyContext); 41 console.log(data); 42 return ( 43
44

孙子

45

{data.count}

46 47
48 ); 49 }

RefHook

在函数组件里面我们可以使用userRef这个Hook获取一个元素或者组件的引用

 1  import React, { useEffect, useRef } from "react";
 2  ?
 3  export default function RefHook() {
 4    const btn = useRef();
 5    // 在componentDidMount后获取
 6    useEffect(() => {
 7      console.log(btn.current);
 8    }, []);
 9    return (
10      
11 12
13 ); 14 }

ReducerHook

useReducer是useState的替代方案,当useState里面的逻辑相对复杂的时候,我们可以使用useReducer来代替。

useRducer的基本使用步骤如下:

a.准备一个初始state数据和操作state的方法
 1  // 初始state
 2  const state = {
 3    count: 0,
 4  };
 5  // 操作state的方法reducer
 6  // aciont里面一般是type和pyload两个属性用来判断不同的复杂逻辑
 7  const reducer = (st = state, action) => {
 8    const state = JSON.parse(JSON.stringify(st));
 9    // 通过判断不同的action来处理不同的逻辑
10    switch (action.type) {
11      case "add":
12        state.count += action.pyload;
13        break;
14      case "reduce":
15        state.count -= action.pyload;
16        break;
17    }
18    // reducer一定要返回一个新的state
19    return state;
20  };
b.调用useReducer这个Hook来得到state和dispatch
 export default function ReducerHook() {
   // state就是我们需要维护的数据,dispatch是一个方法,用来调用reducer的
   const [state, dispatch] = useReducer(reducer, initState);
   return (
     
ReducerHook
state's count : {state.count}
{/* dispatch方法传入一个action来激活reducer里面对应的操作 */}
); }

其它Hook

上述的那些已经是我们平时比较常用的hook,当然hook不是只有这些,如果想了解,戳这里

 

练手小目标:

1.能使用useState实现函数式组件的响应式数据。

2.能使用useContext实现多级组件间的数据传递。

3.能使用useEffect模拟生命周期。

4.能使用useRef获取DOM元素的引用。

5.能使用useReducer实现响应式数据操作。