【React 进阶】函数组件中 React Hooks 详解与实践

27 篇文章 4 订阅
7 篇文章 4 订阅

时隔一年半之久再次重新学习 React,好多都还是原来的样子,这次我要重新开启 React 的大门,希望各位小伙伴可以一起讨论学习呦~

前言

今天我们开启第四个专题:函数组件中 React Hooks 详解与实践。
在 16.8 版本之后的 React 发布了新特性 Hooks。 本篇文章主要对该新特性进行了详细讲解,并对一些常用的 Hooks 进行代码演示,希望可以对需要的小伙伴提供一些帮助。

一、什么是 Hooks ?

Hooks 是 React v16.7.0-alpha 中加入的新特性。它可以让你在 class 以外使用 state 和其他 React 特性。
这个 API 是 React 的未来,各位有必要深入理解。

Hook 这个单词的意思是"钩子"。

React Hooks 的意思是:组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。 React Hooks 就是那些钩子。

当我们需要什么功能,就使用什么钩子。React 默认提供了一些常用钩子,你也可以封装自己的钩子。

所有的钩子都是为函数引入外部功能,所以 React 约定,钩子一律使用 use 前缀命名,便于识别。你要使用 xxx 功能,钩子就命名为 usexxx。

二、Hooks 怎么用 ?

比如:useState 就是一个 Hook,可以在我们不使用 class 组件的情况下,拥有自身的 state,并且可以通过修改 state 来控制 UI 的展示。

import React, { useState } from 'react';

function Foo() {
    // 声明一个名为 “count” 的新状态变量
    const [count, setCount] = useState(0);

    return (
        <div>
            <p>You clicked {count} times</p>
            <button onClick={() => setCount(count + 1)}>
                Click me
            </button>
        </div>
    );
}

export default Foo;

是不是在函数式组件里使用 Hooks 很方便?那我们在对比一下实现同样的功能,在类组件中使用呢。

import React, { Component } from "react";

export default class Foo extends Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        };
    }

    render() {
        return (
            <div>
            <p>You clicked {this.state.count} times</p>
            <button onClick={() => this.setState({ count: this.state.count + 1 })}>
                Click me
            </button>
            </div>
        );
    }
}

这个类组件仅仅是实现了一个点击累加的功能,但可以看到,它的代码已经很"重"了。真实的 React App 由多个类按照层级,一层层构成,复杂度成倍增长。再加入 Redux,就变得更复杂。

三、Hooks 有哪些 ?

常用的几个:
useState()
useEffect()
useReducer()
useContext()
简单了解:
useCallback()
useMemo()
useRef()
useLayoutEffect()
useImperativeHandle()

1、useState

  • 语法

    const [state, setState] = useState(initialState)
    // 传入唯一的参数: initialState,可以是数字,字符串等,也可以是对象或者数组。
    // 返回的是包含两个元素的数组:第一个元素,state 变量,setState 修改 state 值的方法。
    
  • 优化方案

    在创建初始状态是比较昂贵的,所以我们可以在使用 useState API 时,传入一个函数,就可以避免重新创建忽略的初始状态。

    // createRows 只会被执行一次
    const [rows, setRows] = useState(() => createRows(props.count));
    

2、useEffect

之前很多具有副作用的操作,例如网络请求,修改 UI 等,一般都是在 class 组件的 componentDidMount 或者 componentDidUpdate 等生命周期中进行操作。而在函数组件中是没有这些生命周期的概念的,只能 return 想要渲染的元素。
但是现在,在函数组件中也有执行副作用操作的地方了,就是使用 useEffect 函数。

  • 语法

    useEffect(() => { doSomething });
    /*
    * 参数:
    * 第一个是一个函数,是在第一次渲染以及之后更新渲染之后会进行的副作用。
    * 	这个函数可能会有返回值,倘若有返回值,返回值也必须是一个函数,会在组件被销毁时执行。
    * 第二个参数是可选的,是一个数组,数组中存放的是第一个函数中使用的某些副作用属性。用来优化 useEffect
    * 	如果使用此优化,请确保该数组包含外部作用域中随时间变化且 effect 使用的任何值。 否则,您的代码将引用先前渲染中的旧值。
    * 	如果要运行 effect 并仅将其清理一次(在装载和卸载时),则可以将空数组([])作为第二个参数传递。 这告诉 React 你的 effect 不依赖于来自 props 或 state 的任何值,所以它永远不需要重新运行。
    */
    
  • 注意

    虽然传递 [] 更接近熟悉的 componentDidMountcomponentWillUnmount 执行规则,但我们建议不要将它作为一种习惯,因为它经常会导致错误。

  • 优化方案

    useEffect 的第二个参数是一个数组,里面放入在 useEffect 使用到的 state 值,可以用作优化,只有当数组中 state 值发生变化时,才会执行这个 useEffect

    useEffect(() => {
        // 使用浏览器API更新文档标题
        document.title = `You clicked ${count} times`;
    }, [ count ]);
    

    Tip:如果想模拟 class 组件的行为,只在 componetDidMount 时执行副作用,在 componentDidUpdate 时不执行,那么 useEffect 的第二个参数传一个 [] 即可。(但是不建议这么做,可能会由于疏漏出现错误)

3、useReducer

  • 语法

    const [state, dispatch] = useReducer(reducer, initialArg, init);
    

    useState 的替代方案。 接受类型为 (state, action) => newState 的reducer,并返回与 dispatch 方法配对的当前状态。
    当你涉及多个子值的复杂 state(状态) 逻辑时,useReducer 通常优于 useState

  • 优化:延迟初始化

    还可以惰性地创建初始状态。为此,你可以将init函数作为第三个参数传递。初始状态将设置为 init(initialArg)

  • useState 的区别

    • state 状态值结构比较复杂时,使用 useReducer 更有优势。
    • 使用 useState 获取的 setState 方法更新数据时是异步的;而使用 useReducer 获取的 dispatch 方法更新数据是同步的。

4、useContext

  • 语法

    const value = useContext(MyContext);
    
    • 接受上下文对象(从中 React.createContext 返回的值)并返回该上下文的当前上下文值。当前上下文值由树中调用组件上方 value 最近的 prop 确定 <MyContext.Provider>。
    • useContext(MyContext) 则相当于 static contextType = MyContext 在类中,或者 <MyContext.Consumer>。
  • 注意

    useContext 必须是上下文对象本身的参数:

    useContext(MyContext)
    

    useContext(MyContext) 只允许您阅读上下文并订阅其更改。您仍然需要 <MyContext.Provider> 在树中使用以上内容来为此上下文提供值。

5、

其他后面几个 Hooks 的用法我将在最近进行补充,感谢大家支持!

四、自定义 Hooks ?

后续待补充…

五、使用 Hooks 需要注意什么?

  1. 不要从常规 JavaScript 函数调用 Hooks;
  2. 不要在循环,条件或嵌套函数中调用 Hooks;
  3. 必须在组件的顶层调用 Hooks;
  4. 可以从 React 功能组件调用 Hooks;
  5. 可以从自定义 Hooks 中调用 Hooks;
  6. 自定义 Hooks 必须使用 use 开头,这是一种约定;

希望以上内容可以帮助到大家。我也是重新开始学习 React,欢迎大家一起讨论学习,最后不要忘记一键三连哦~

如果有什么不对或不严谨的地方,欢迎大家能提出宝贵的意见,十分感谢。

各位 加油!

参考文档:
React 官网
React Hooks FAQ

写在最后

原 创 不 易 , 还 希 望 各 位 大 佬 支 持 一 下 \textcolor{blue}{原创不易,还希望各位大佬支持一下}

👍 点 赞 , 你 的 认 可 是 我 创 作 的 动 力 ! \textcolor{green}{点赞,你的认可是我创作的动力!}

⭐️ 收 藏 , 你 的 青 睐 是 我 努 力 的 方 向 ! \textcolor{green}{收藏,你的青睐是我努力的方向!}

✏️ 评 论 , 你 的 意 见 是 我 进 步 的 财 富 ! \textcolor{green}{评论,你的意见是我进步的财富!}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值