React Hooks 基本使用

这篇具有很好参考价值的文章主要介绍了React Hooks 基本使用。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

  • class 组件如果业务复杂,很难拆分和重构,很难测试;相同业务逻辑分散到各个方法中,逻辑混乱
  • 逻辑复用像HOCRender Props,不易理解,学习成本高
  • React提倡函数式编程,函数更易拆分,更易测试
  • 但是函数组件太简单,为了增强函数组件的功能,媲美class组件:
    • 函数组件没有statesetState
    • 函数组件没有生命周期

React Hooks 使用规范

  • 只能用于 React 函数组件和自定义Hook 中,其他地方不可以
  • 只能用于顶层代码,不能在循环、判断中使用Hooks
  • eslint 插件 eslint-plugin-react-hooks

基本使用

useState

  • 可用于模拟class组件的statesetState
import React, { useState } from 'react';

function ClickCounter() {
    // 数组的解构
    // useState 是最基本的一个 Hook
    const [count, setCount] = useState(0); // 传入一个初始值

    const [name, setName] = useState('章三');

    // const arr = useState(0);
    // const count = arr[0];
    // const setCount = arr[1];

    function clickHandler() {
        setCount(count + 1);
        setName(name + '2020');
    }

    return (<div>
        <p>你点击了 {count}{name}</p>
        <button onClick={clickHandler}>点击</button>
    </div>);
}

export default ClickCounter;

useEffect 模拟生命周期

  • 默认函数组件没有生命周期
  • 函数组件是一个纯函数,执行完即销毁,自己无法实现生命周期
  • 使用 Effect hooks 可以把生命周期“钩”到函数组件中

useEffect 中返回函数 fn

  • useEffect 依赖[],组件销毁是执行fn,等于 componentWillUnmount
  • useEffect 无依赖或依赖[a,b],组件更新时执行 fn,即下一次执行useEffect之前,就会执行fn,无论更新或卸载
import React, { useState, useEffect } from 'react';

function LifeCycles() {
    const [count, setCount] = useState(0);
    const [name, setName] = useState('章三');

    // // 模拟 class 组件的 DidMount 和 DidUpdate
    // useEffect(() => {
    //     console.log('在此发送一个 ajax 请求');
    // });

    // // 模拟 class 组件的 DidMount
    // useEffect(() => {
    //     console.log('加载完了');
    // }, []) // 第二个参数是 [] (不依赖于任何 state);

    // // 模拟 class 组件的 DidUpdate
    // useEffect(() => {
    //     console.log('更新了');
    // }, [count, name]); // 第二个参数就是依赖的 state

    // 模拟 class 组件的 DidMount
    useEffect(() => {
        let timerId = window.setInterval(() => {
            console.log(Date.now());
        }, 1000);

        // 返回一个函数
        // 模拟 WillUnMount
        return () => {
            window.clearInterval(timerId);
        };
    }, []);

    function clickHandler() {
        setCount(count + 1);
        setName(name + '2020');
    }

    return (<div>
        <p>你点击了 {count}{name}</p>
        <button onClick={clickHandler}>点击</button>
    </div>);
}

export default LifeCycles;

模拟 componentWillUnMount 注意事项

import React from 'react';

class FriendStatus extends React.Component {
    constructor(props) {
        super(props);
        
        this.state = {
            status: false // 默认当前不在线
        };
    }
    
    render() {
        return (<div>
            好友 {this.props.friendId} 在线状态:{this.state.status}
        </div>);
    }
    
    componentDidMount() {
        console.log(`开始监听 ${this.props.friendId} 的在线状态`);
    }
    
    componentWillUnmount() {
        console.log(`结束监听 ${this.props.friendId} 的在线状态`);
    }
    
    // friendId 更新
    componentDidUpdate(prevProps) {
        console.log(`结束监听 ${prevProps.friendId} 在线状态`);
        console.log(`开始监听 ${this.props.friendId} 在线状态`);
    }
}

export default FriendStatus;
import React, { useState, useEffect } from 'react';

function FriendStatus({ friendId }) {
    const [status, setStatus] = useState(false);

    // DidMount 和 DidUpdate
    useEffect(() => {
        console.log(`开始监听 ${friendId} 在线状态`);

        // 【特别注意】
        // 此处并不完全等同于 componentWillUnMount
        // props 发生变化,即更新,也会执行结束监听
        // 准确的说:返回的函数,会在下一次 effect 执行之前,被执行
        return () => {
            console.log(`结束监听 ${friendId} 在线状态`);
        };
    });

    return (<div>
        好友 {friendId} 在线状态:{status.toString()}
    </div>);
}

export default FriendStatus;

useRef

  • 获取 dom 节点
import React, { useRef, useEffect } from 'react';

function UseRef() {
    const btnRef = useRef(null); // 初始值

    // const numRef = useRef(0);
    // numRef.current;

    useEffect(() => {
        console.log(btnRef.current); // DOM 节点
    }, []);

    return (<div>
        <button ref={btnRef}>click</button>
    </div>);
}

export default UseRef;

useContext

  • 定义一个主题,可隔层传递
import React, { useContext } from 'react';

// 主题颜色
const themes = {
    light: {
        foreground: '#000',
        background: '#eee'
    },
    dark: {
        foreground: '#fff',
        background: '#222'
    }
};

// 创建 Context
const ThemeContext = React.createContext(themes.light); // 初始值

function ThemeButton() {
    const theme = useContext(ThemeContext);

    return (<button style={{ background: theme.background, color: theme.foreground }}>
        hello world
    </button>);
}

function Toolbar() {
    return (<div>
        <ThemeButton></ThemeButton>
    </div>);
}

function App() {
    return (<ThemeContext.Provider value={themes.dark}>
        <Toolbar></Toolbar>
    </ThemeContext.Provider>);
}

export default App;

useReducer

useReducer 和 redux 的区别:

  • useReduceruseState的代替方案,用于state 复杂变化
  • useReducer 是单个组件状态管理,组件通讯还需要props
  • redux 是全局的状态管理,多组件共享数据
import React, { useReducer } from 'react';

const initialState = { count: 0 };

const reducer = (state, action) => {
    switch (action.type) {
        case 'increment':
            return { count: state.count + 1 };
        case 'decrement':
            return { count: state.count - 1 };
        default:
            return state;
    }
};

function App() {
    // 很像 const [count, setCount] = useState(0)
    const [state, dispatch] = useReducer(reducer, initialState);

    return (<div>
        count: {state.count}
        <button onClick={() => dispatch({ type: 'increment' })}>increment</button>
        <button onClick={() => dispatch({ type: 'decrement' })}>decrement</button>
    </div>);
}

export default App;

useMemo

  • React 默认会更新所有子组件
  • class 组件使用 SCUPureComponent做优化
  • Hooks 中使用useMemo,但优化的原理是相同的

使用 useMemo做性能优化:

  • useMemo 缓存值
  • 依赖不变,useMemo会取上一次缓存的值,一般用于避免复杂计算。
import React, { useState, memo, useMemo } from 'react';

// 子组件
// function Child({ userInfo }) {
//     console.log('Child render...', userInfo);

//     return (<div>
//         <p>This is Child {userInfo.name} {userInfo.age}</p>
//     </div>);
// }

// 类似 class PureComponent ,对 props 进行浅层比较
const Child = memo(({ userInfo }) => {
    console.log('Child render...', userInfo);

    return (<div>
        <p>This is Child {userInfo.name} {userInfo.age}</p>
    </div>);
});

// 父组件
function App() {
    console.log('Parent render...');

    const [count, setCount] = useState(0);
    const [name, setName] = useState('章三');

    // const userInfo = { name, age: 20 }
    // 用 useMemo 缓存数据,有依赖
    const userInfo = useMemo(() => {
        return { name, age: 21 };
    }, [name]);

    return (<div>
        <p>
            count is {count}
            <button onClick={() => setCount(count + 1)}>click</button>
        </p>
        <Child userInfo={userInfo}></Child>
    </div>);
}

export default App;

useCallback

使用 useCallback做性能优化:

  • useCallback 缓存函数
  • 依赖不变,useCallback会取上一次缓存的函数,一般用于父组件给子组件传递函数,减少子组件的渲染次数。
import React, { useState, memo, useMemo, useCallback } from 'react';

// 子组件,memo 相当于 PureComponent
const Child = memo(({ userInfo, onChange }) => {
    console.log('Child render...', userInfo);

    return (<div>
        <p>This is Child {userInfo.name} {userInfo.age}</p>
        <input onChange={onChange}></input>
    </div>);
});

// 父组件
function App() {
    console.log('Parent render...');

    const [count, setCount] = useState(0);
    const [name, setName] = useState('章三');

    // 用 useMemo 缓存数据
    const userInfo = useMemo(() => {
        return { name, age: 21 };
    }, [name]);

    // function onChange(e) {
    //     console.log(e.target.value);
    // }
    
    // 用 useCallback 缓存函数
    const onChange = useCallback(e => {
        console.log(e.target.value);
    }, []);

    return (<div>
        <p>
            count is {count}
            <button onClick={() => setCount(count + 1)}>click</button>
        </p>
        <Child userInfo={userInfo} onChange={onChange}></Child>
    </div>);
}

export default App;

自定义 hooks

作用:

  • 封装通用的功能
  • 开发和使用第三方 Hooks
  • 自定义 Hook 带来了无限的扩展性,解耦代码

使用:

  • 本质是一个函数,以 use 开头
  • 内部正常使用 useStateuseEffect 获取其他 Hooks
  • 自定义返回结果,格式不限
import { useState, useEffect } from 'react';

function useMousePosition() {
    const [x, setX] = useState(0);
    const [y, setY] = useState(0);

    useEffect(() => {
        function mouseMoveHandler(event) {
            setX(event.clientX);
            setY(event.clientY);
        }

        // 绑定事件
        document.body.addEventListener('mousemove', mouseMoveHandler);

        // 解绑事件
        return () => document.body.removeEventListener('mousemove', mouseMoveHandler);
    }, []);

    return [x, y];
}

export default useMousePosition;
import { useState, useEffect } from 'react';
import axios from 'axios';

// 封装 axios 发送网络请求的自定义 Hook
function useAxios(url) {
    const [loading, setLoading] = useState(false);
    const [data, setData] = useState();
    const [error, setError] = useState();

    useEffect(() => {
        // 利用 axios 发送网络请求
        setLoading(true);
        
        axios.get(url) // 发送一个 get 请求
            .then(res => setData(res))
            .catch(err => setError(err))
            .finally(() => setLoading(false));
    }, [url]);

    return [loading, data, error];
}

export default useAxios;

// 第三方 Hook
// https://nikgraf.github.io/react-hooks/
// https://github.com/umijs/hooks

hooks 注意事项

  • useState 初始化值只有第一次有效
  • useEffect 内部不能修改 state
  • useEffect 可能出现死循环
// 关于 useEffect 内部不能修改 state 的问题
import { useEffect, useState } from 'react';

const HelloWorld = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const timer = setInterval(() => {
      setCount(pre => pre + 1);
    }, 1000);

    return () => clearInterval(timer);
  }, []);

  return (<p>{count}</p>);
}

export default HelloWorld;

为何 hooks 要依赖于调用顺序?

import React, { useState, useEffect } from 'react';

function Teach({ couseName }) {
    // 函数组件,纯函数,执行完即销毁
    // 所以,无论组件初始化(render)还是组件更新(re-render)
    // 都会重新执行一次这个函数,获取最新的组件
    // 这一点和 class 组件不一样

    // render: 初始化 state 的值 '张三'
    // re-render: 读取 state 的值 '张三'
    const [studentName, setStudentName] = useState('张三');

    // if (couseName) {
    //     const [studentName, setStudentName] = useState('张三');
    // }

    // render: 初始化 state 的值 '里斯'
    // re-render: 读取 state 的值 '里斯'
    const [teacherName, setTeacherName] = useState('里斯')

    // if (couseName) {
    //     useEffect(() => {
    //         // 模拟学生签到
    //         localStorage.setItem('name', studentName);
    //     });
    // }

    // render: 添加 effect 函数
    // re-render: 替换 effect 函数(内部的函数也会重新定义)
    useEffect(() => {
        // 模拟学生签到
        localStorage.setItem('name', studentName);
    });

    // render: 添加 effect 函数
    // re-render: 替换 effect 函数(内部的函数也会重新定义)
    useEffect(() => {
        // 模拟开始上课
        console.log(`${teacherName} 开始上课,学生 ${studentName}`);
    });

    return (<div>
        课程:{couseName},
        讲师:{teacherName},
        学生:{studentName}
    </div>);
}

export default Teach;

FQA

  1. 为什么会有 React hooks
  • class 组件不易拆分、不易测试、业务代码分散在各个方法中
  • 函数组件更易拆分和测试;但是函数组件没有state和生命周期,所以需要使用hooks来增强函数组件的功能
  1. React hooks 如何模拟生命周期?
  • 模拟componentDidMount - useEffect 依赖 []
  • 模拟componentDidUpdate - useEffect 无依赖,或者依赖 [a,b]
  • 模拟componentWillUnMount - useEffect 依赖 [],并返回一个函数
  1. 如何自定义hooks
  • use 开头,定义一个函数
  • 内部正常使用 useStateuseEffect 获取其他 Hooks
  • 自定义返回结果,格式不限
  1. 为什么要使用 hooks?
  • 完善函数组件的能力,函数更适合React组件
  • 组件逻辑复用,hooks表现更好
  1. hooks 组件逻辑复用的好处?
  • HOC 组件层级嵌套过多,不易渲染,不易调试; HOC 会劫持props,必须严格规范,容易出现疏漏
  • Render Props 学习成本高,不易理解;只能传递纯函数,而默认情况下纯函数功能有限
  • hooks 做组件逻辑复用,完全符合hooks原有原则,没有其他要求,易理解记忆;变量作用域明确;不会产生组件嵌套
  1. React hooks 容易遇到哪些坑?
  • useState 初始化值,只能初始化一次
  • useEffect 内部不能修改 state
  • useEffect 依赖引用类型,可能会出现死循环

React 18 新增 hooks?

useTransition

使用useTransition来降低渲染优先级, 可以指定 UI 的渲染优先级,哪些需要实时更新,哪些需要延迟更新。

useDefferdValue

允许变量延时更新,接收一个可选的延迟更新的最长时间

userId

使用 useId 可以生成客户端与服务端之间的唯一id ,并且返回一个字符串。

useSyncExternalStore

可以使 React 在并发模式下,保持自身 state 和来自 redux 的状态同步。

useInsertionEffect

useInsertionEffect 可以在布局副作用触发之前将元素插入到 DOM 中。文章来源地址https://www.toymoban.com/news/detail-809881.html

到了这里,关于React Hooks 基本使用的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • React Hooks 详细使用介绍

    useState 是 React 中的一个基础 Hook,允许你在不使用 class 组件的情况下管理组件状态。 参数 初始值 你可以直接传递状态的初始值给 useState : 使用函数设置初始值 当初始化状态代价较大时,你可以传递一个函数: 返回值 useState 返回一个数组,其中包括当前状态值和一个更新

    2024年02月13日
    浏览(30)
  • react中hooks的理解与使用

    一、作用 我们知道react组件有两种写法一种是类组件,另一种是函数组件。而函数组件是无状态组件,如果我们要想改变组件中的状态就无法实现了。为此,在react16.8版本后官方推出hooks,用于函数组件更改状态。 二、常用API 1、useState :存储变量和修改变量 用法: 有两个参

    2024年02月13日
    浏览(34)
  • React - Redux Hooks的使用细节详解

    Redux中Hooks介绍 在之前的redux开发中,为了让组件和redux结合起来,我们使用了react-redux库中的connect : 但是这种方式必须使用高阶函数结合返回的高阶组件; 并且必须编写:mapStateToProps和 mapDispatchToProps映射的函数, 具体使用方式在前面文章有讲解; 在Redux7.1开始,提供了Hook的方式

    2024年02月02日
    浏览(49)
  • React Hooks的useState、useRef使用

    React Hooks 是 React 16.8 版本引入的新特性,它允许你在不编写 class 的情况下使用 state 和其他 React 特性。其中, useState  和  useRef  是两个常用的 Hooks。 1. useState useState  是一个允许你在函数组件中添加 state 的 Hook。 使用说明: useState  返回一个状态变量和一个设置该变量的函

    2024年02月02日
    浏览(40)
  • React的10个常用Hooks及使用场景

    React是一款非常流行的JavaScript库,它提供了许多Hooks,用于管理函数组件的状态和生命周期。下面是React的每个Hooks的使用场景和示例: useState用于在函数组件中管理状态。 它返回一个包含当前状态和一个更新状态的函数的数组。更新状态的函数可以接受一个新的值,并更新状

    2024年02月09日
    浏览(32)
  • 【《React Hooks实战》——指导你使用hook开发性能优秀可复用性高的React组件】

    使用React Hooks后,你很快就会发现,代码变得更具有组织性且更易于维护。React Hooks是旨在为用户提供跨组件的重用功能和共享功能的JavaScript函数。利用React Hooks, 可以将组件分成多个函数、管理状态和副作用,并且不必声明类即可调用React内置的功能。而且,上述所有的操作

    2024年02月14日
    浏览(34)
  • react 【七】各种hooks的使用/SPA的缺点

    依然需要在index.js使用context 1.8.1 ref绑定dom 1.8.2 ref解决闭包缺陷 1.11.1 什么是自定义Hook 1.11.2 Context的共享 Hook 1.11.3 获取鼠标滚动位置 1.11.4 storage SPA页面 1、不利于SEO优化搜索引擎优化 2、首屏渲染速度慢 1、不利于SEO优化搜索引擎优化 例如百度页面在进行收录的时候 是

    2024年02月20日
    浏览(32)
  • React的7个常用Hooks及使用场景(含示例)

    React是一款非常流行的JavaScript库,它提供了许多Hooks,用于管理函数组件的状态和生命周期。下面是React的每个Hooks的使用场景和示例: useState用于在函数组件中管理状态。 它返回一个包含当前状态和一个更新状态的函数的数组。更新状态的函数可以接受一个新的值,并更新状

    2024年02月10日
    浏览(31)
  • React 中与生命周期相关的 Hooks 及其使用示例

    React 16.8 引入了 Hooks 的概念,使得函数组件也可以使用 state 和生命周期等特性。与生命周期相关的 Hooks 主要有以下三个: useEffect useEffect 是最常用的一个 Hook,它可以用来替代 class 组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount 这三个生命周期函数。useEffect 的作

    2024年04月14日
    浏览(30)
  • react之Hooks的介绍、useState与useEffect副作用的使用

    Hooks 是 React v16.8 中的新增功能 为函数组件提供状态、生命周期等原本 class 组件中提供的 React 功能 可以理解为通过 Hooks 为函数组件钩入 class 组件的特性 注意:Hooks 只能在函数组件中使用,自此,函数组件成为 React 的新宠儿 可以在项目中同时使用hooks和class 一个 Hook 就是一

    2024年02月12日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包