开发中常用的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 <div>
12 <p>You clicked {count} times</p>
13 <button onClick={() => setCount(count + 1)}>
14 Click me
15 </button>
16 </div>
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 <div>
20 <p>Count:{count}</p>
21 <p>Double:{double}</p>
22 <button onClick={onClick}>++</button>
23 </div>
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 <div>
10 {/* 直接渲染对应的数据 */}
11 <p>Count:{count}</p>
12 <button onClick={onClick}>增加</button>
13 </div>
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 <div>
15 <p>Count:{count}</p>
16 <button onClick={onClick}>增加</button>
17 </div>
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 <div>
23 <p>Count:{count}</p>
24 <button onClick={onClick}>增加</button>
25 </div>
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 <MyContext.Provider value={{ count, add }}>
8 <Parent />
9 </MyContext.Provider>
10 );
11 }
c.在后代组件里面使用useContext方法获取Context对象
 1  function Parent() {
2 return (
3 <div>
4 <Child />
5 </div>
6 );
7 }
8 function Child() {
9 const context = useContext(MyContext);
10 return (
11 <div>
12 {/* context对象就是之前的Provider里面的value属性 */}
13 <p>count from ancestors:{context.count}</p>
14 <button onClick={() => context.add(1)}>Add</button>
15 </div>
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 <MyContext.Provider value={{ count, add }}>
30 <Parent />
31 </MyContext.Provider>
32 );
33 }
34 ​
35 function Parent() {
36 return <Child />;
37 }
38 ​
39 function Child() {
40 const data = useContext(MyContext);
41 console.log(data);
42 return (
43 <div>
44 <h3>孙子</h3>
45 <p>{data.count}</p>
46 <button onClick={data.add}>++</button>
47 </div>
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 <div>
11 <button ref={btn}>Button</button>
12 </div>
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 (
<div>
<div>ReducerHook</div>
<div>state's count : {state.count}</div>
{/* dispatch方法传入一个action来激活reducer里面对应的操作 */}
<button onClick={() => dispatch({ type: "add", pyload: 1 })}>Add</button>
<button onClick={() => dispatch({ type: "reduce", pyload: 1 })}>
reduce
</button>
</div>
);
}

其它Hook

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

练手小目标:

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

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

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

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

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

开发中常用的Hook的更多相关文章

  1. .net开发中常用的第三方组件

    .net开发中常用的第三方组件 2013-05-09 09:33:32|  分类: dotnet |举报 |字号 订阅     下载LOFTER 我的照片书  |   RSS.NET.dll RSS. ...

  2. 依赖注入及AOP简述(十)——Web开发中常用Scope简介 .

    1.2.    Web开发中常用Scope简介 这里主要介绍基于Servlet的Web开发中常用的Scope. l        第一个比较常用的就是Application级Scope,通常我们会将一 ...

  3. spring注解开发中常用注解以及简单配置

    一.spring注解开发中常用注解以及简单配置 1.为什么要用注解开发:spring的核心是Ioc容器和Aop,对于传统的Ioc编程来说我们需要在spring的配置文件中邪大量的bean来向sprin ...

  4. Android源码浅析(四)——我在Android开发中常用到的adb命令,Linux命令,源码编译命令

    Android源码浅析(四)--我在Android开发中常用到的adb命令,Linux命令,源码编译命令 我自己平时开发的时候积累的一些命令,希望对你有所帮助 adb是什么?: adb的全称为Andr ...

  5. 2019-2-20C#开发中常用加密解密方法解析

    C#开发中常用加密解密方法解析 一.MD5加密算法 我想这是大家都常听过的算法,可能也用的比较多.那么什么是MD5算法呢?MD5全称是 message-digest algorithm 5[|ˈmes ...

  6. 开发中常用的es6知识

    结合实际开发,开发中常用的es6的知识: 1.新增let和const命令: ES6 新增了let命令,用来声明变量.它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效: cons ...

  7. Android开发中常用的库总结(持续更新)

    这篇文章用来收集Android开发中常用的库,都是实际使用过的.持续更新... 1.消息提示的小红点 微信,微博消息提示的小红点. 开源库地址:https://github.com/stefanjau ...

  8. iOS开发中常用的数学函数

    iOS开发中常用的数学函数 /*---- 常用数学公式 ----*/ //指数运算 3^2 3^3 NSLog(,)); //result 9 NSLog(,)); //result 27 //开平方 ...

  9. Struts2页面开发中常用标签使用说明

    1. Struts2页面开发中常用标签使用说明 1.1.往action里传值的使用方式: <input name="userName" type="text&quo ...

随机推荐

  1. 2022 年最受瞩目的新特性 CSS @layer 到底是个啥?

    步入 2022,CSS 的新特性层出不穷,而最近在 CSS 圈最受瞩目的新特性,非 CSS @layer 莫属. 本文,将用最简洁的语言,快速让读者们搞懂,到底什么是 CSS @layer 新规范. ...

  2. 遇到REMOTE HOST IDENTIFICATION HAS CHANGED怎么办?

    今日遇到如下问题: 警告的大概意思就是,主机密钥发生变更,并提示安全风险(可能存在中间人攻击) 但是事实是,这是因为我重装系统之后遇到的问题.重装系统后,指纹当然会发生变化了...在Xshell实验中 ...

  3. minouche

    靶机准备 先将靶机导入虚拟机,并将网络模式改为NAT 扫描不到ip,改VirtualBox,使用桥接,并将kali也改为桥接模式 扫描ip:192.168.0.102 netdiscover -r 1 ...

  4. c# / .net wFramework winform 之运行后的窗体窗口可拖动操作

    学习winform 的同志们可能会有这样的提问,我运行起来的窗体或者窗口该如何实现可拖动呢?今天它来了 思路:可以给窗体增加一个进度条(progressBar控件) 全局定义这几个变量: long p ...

  5. Windows10与Centos7双系统安装踩的坑

    1. 首先安装windows(太简单不说了) 2.然后安装Centos7(太简单不说了) 3.注意:安装完Centos7重启电脑进入系统引导项突然发现没有Windows引导项 0x06 恢复Windo ...

  6. Java中的list和set有什么区别

    list与set方法的区别有:list可以允许重复对象和插入多个null值,而set不允许:list容器是有序的,而set容器是无序的等等 Java中的集合共包含三大类,它们分别是Set(集),Lis ...

  7. 说说has a与is a的区别?

    is a是典型的"一般到特殊"的关系,也就是典型的继承关系.例如Apple is a Fruit.那么Apple是一种特殊的Fruit,也就是说Apple继承了Fruit. has ...

  8. ServletConfig对象和ServletContext对象有什么区别?

    一个Servlet对应有一个ServletConfig对象,可以用来读取初始化参数. 一个webapp对应一个ServletContext对象. ServletContext对象获取初始化定义的参数. ...

  9. kafka 分布式(不是单机)的情况下,如何保证消息的顺序消费?

    Kafka 分布式的单位是 partition,同一个 partition 用一个 write ahead log 组织, 所以可以保证 FIFO 的顺序.不同 partition 之间不能保证顺序. ...

  10. Ribbon负载均衡能干什么?

    (1)将用户的请求平摊的分配到多个服务上 (2)集中式LB即在服务的消费方和提供方之间使用独立的LB设施(可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责把访问请求通过某种策略转发至 ...