大白话React Hooks,新特性怎么用?

啥是 React Hooks

React Hooks 是 React 16.8 版本引入的新特性,它能让你在不编写 class 的情况下使用 state 以及其他的 React 特性。就好比以前你盖房子得用一种特定的建筑方式(class 组件),现在有了新工具(Hooks),不用那种特定方式也能盖出很棒的房子。它可以让你的代码更简洁、更易复用。

常用的 React Hooks 及其使用方法

1. useState
  • 作用 :让你在函数组件里使用 state,就像给函数组件装上了能存储数据的小盒子。
  • 使用方法 :它接收一个初始值作为参数,返回一个数组,数组的第一个元素是当前的 state 值,第二个元素是一个函数,用于更新这个 state
jsx 复制代码
import React, { useState } from 'react';

function Counter() {
    // 定义一个名为 count 的 state,初始值为 0
    // useState 返回一个数组,第一个元素是 count 的值,第二个元素是更新 count 的函数 setCount
    const [count, setCount] = useState(0);

    return (
        <div>
            {/* 显示 count 的值 */}
            <p>你点击了 {count} 次</p>
            {/* 点击按钮时调用 setCount 函数,将 count 的值加 1 */}
            <button onClick={() => setCount(count + 1)}>
                点击我
            </button>
        </div>
    );
}

export default Counter;
2. useEffect
  • 作用:可以让你在函数组件里执行副作用操作,比如数据获取、订阅、手动修改 DOM 等。就像在房子盖好后,你可以用它来做一些额外的装饰或者布置。
  • 使用方法:它接收一个回调函数作为第一个参数,这个回调函数会在组件渲染后执行。第二个参数是一个可选的数组,用于指定哪些值发生变化时才执行这个回调函数。如果不传第二个参数,回调函数会在每次组件渲染后都执行;如果传一个空数组,回调函数只会在组件第一次渲染后执行。
jsx 复制代码
import React, { useState, useEffect } from 'react';

function DataFetcher() {
    // 定义一个名为 data 的 state,初始值为 null
    const [data, setData] = useState(null);

    // 使用 useEffect 进行数据获取
    useEffect(() => {
        // 模拟一个异步的数据获取操作
        const fetchData = async () => {
            const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
            const result = await response.json();
            // 将获取到的数据更新到 data state 中
            setData(result);
        };

        // 调用数据获取函数
        fetchData();

        // 可以返回一个清理函数,用于在组件卸载时执行一些清理操作,比如取消订阅等
        return () => {
            console.log('组件卸载了');
        };
    }, []); // 传入空数组,表示这个 useEffect 只在组件第一次渲染后执行

    return (
        <div>
            {data? (
                // 如果 data 不为 null,显示数据的标题
                <p>{data.title}</p>
            ) : (
                // 如果 data 为 null,显示加载中
                <p>加载中...</p>
            )}
        </div>
    );
}

export default DataFetcher;
3. useContext
  • 作用 :让你在函数组件里使用 React 的上下文(Context),可以方便地在组件树中传递数据,而不用一层一层地通过 props 传递。就像有一个公共的仓库,所有组件都能去里面拿东西。
  • 使用方法 :它接收一个 Context 对象作为参数,返回这个 Context 当前的值。
jsx 复制代码
import React, { createContext, useContext } from 'react';

// 创建一个 Context 对象,初始值为 '默认值'
const MyContext = createContext('默认值');

function ChildComponent() {
    // 使用 useContext 获取 MyContext 的值
    const value = useContext(MyContext);

    return (
        <div>
            {/* 显示从上下文获取的值 */}
            <p>从上下文获取的值: {value}</p>
        </div>
    );
}

function ParentComponent() {
    return (
        // 使用 MyContext.Provider 提供一个新的值 '新的值'
        <MyContext.Provider value="新的值">
            <ChildComponent />
        </MyContext.Provider>
    );
}

export default ParentComponent;
4. useReducer
  • 作用 :是 useState 的替代方案,适用于复杂的 state 逻辑,比如多个子值或者下一个 state 依赖于之前的 state。就像一个更强大的 state 管理工具。
  • 使用方法 :它接收一个 reducer 函数和一个初始 state 作为参数,返回一个数组,数组的第一个元素是当前的 state 值,第二个元素是一个 dispatch 函数,用于触发 reducer 中的操作。
jsx 复制代码
import React, { useReducer } from 'react';

// 定义一个 reducer 函数,接收当前 state 和一个 action,返回新的 state
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 CounterWithReducer() {
    // 使用 useReducer 定义 state 和 dispatch 函数
    const [state, dispatch] = useReducer(reducer, { count: 0 });

    return (
        <div>
            {/* 显示 count 的值 */}
            <p>你点击了 {state.count} 次</p>
            {/* 点击按钮时调用 dispatch 函数,触发 increment 操作 */}
            <button onClick={() => dispatch({ type: 'increment' })}>
                增加
            </button>
            {/* 点击按钮时调用 dispatch 函数,触发 decrement 操作 */}
            <button onClick={() => dispatch({ type: 'decrement' })}>
                减少
            </button>
        </div>
    );
}

export default CounterWithReducer;

通过这些 Hooks,你可以在函数组件里实现很多原本 class 组件才能实现的功能,让代码更加简洁和易于维护。

如何优化使用React Hooks的代码性能?

咱来唠唠怎么优化使用 React Hooks 的代码性能,下面从几个方面详细说说:

别让组件瞎渲染

  • 给组件加个"检查器"React.memo 就像是个检查官,能帮函数组件检查传入的 props 有没有变化。要是 props 和上次一样,它就不让组件重新渲染,省了不少力气。比如说你有个组件专门显示用户信息,只要用户信息的 props 没改,这个组件就不用重新画一遍,这样性能就提升了。代码大概这么写:
jsx 复制代码
import React from'react';
// 用 React.memo 包裹组件
const UserInfo = React.memo(({ name, age }) => {
    return (
        <div>
            <p>姓名: {name}</p>
            <p>年龄: {age}</p>
        </div>
    );
});
export default UserInfo;
  • 缓存计算结果useMemo 就像个小仓库,能把一些计算结果存起来。要是依赖的东西没变化,就直接从仓库里拿结果,不用重新算一遍。比如你有个组件要对一个数组里的数字做复杂计算,每次数组没变就不用重新算,直接用之前算好的结果就行。代码示例如下:
jsx 复制代码
import React, { useMemo } from'react';
function CalculateList({ numbers }) {
    const calculatedResult = useMemo(() => {
        // 假设这里是复杂的计算逻辑
        return numbers.map(num => num * 2);
    }, [numbers]);
    return (
        <ul>
            {calculatedResult.map(result => (
                <li key={result}>{result}</li>
            ))}
        </ul>
    );
}
export default CalculateList;

用好 useEffect

  • 精准设置依赖项useEffect 就像个小跟班,会在组件渲染后做一些额外的事儿。但你得告诉它什么时候该干活,这就靠依赖项数组。要是依赖项数组是空的,它就只在组件刚创建和销毁的时候干活;要是数组里有东西,这些东西变了它才会重新干活。比如说你有个组件要在 count 变化时发个网络请求,那就把 count 放进依赖项数组里。代码如下:
jsx 复制代码
import React, { useState, useEffect } from'react';
function MyComponent() {
    const [count, setCount] = useState(0);
    useEffect(() => {
        // 只有 count 变化时才会发请求
        console.log(`Count 变成了 ${count}`);
        // 这里可以放网络请求的代码
    }, [count]);
    return (
        <div>
            <button onClick={() => setCount(count + 1)}>加 1</button>
        </div>
    );
}
export default MyComponent;
  • 别在 useEffect 里瞎更新 :要是在 useEffect 里做了会让组件重新渲染的事儿,得确保这事儿是必要的,不然就会陷入无限循环,像个疯了的小陀螺。你可以用 useRef 来保存一些临时状态,避免不必要的更新。

优化事件处理

  • 缓存事件处理函数useCallback 就像个函数小管家,能把事件处理函数存起来。每次组件渲染时,只要依赖项没变,它就还是用原来的函数,不用重新创建一个新的。比如你有个按钮的点击事件处理函数,用 useCallback 缓存后,性能会更好。代码如下:
jsx 复制代码
import React, { useState, useCallback } from'react';
function MyButton() {
    const [count, setCount] = useState(0);
    const handleClick = useCallback(() => {
        setCount(count + 1);
    }, [count]);
    return <button onClick={handleClick}>点击我</button>;
}
export default MyButton;

其他小窍门

  • 把大组件拆成小零件:要是一个组件功能太多、太复杂,就把它拆成好几个小的、功能单一的组件。这样每个小组件好维护,也容易复用,性能自然就上去了。
  • 别在循环里乱用 Hooks:React 规定 Hooks 只能在组件最外面或者自定义 Hooks 里面用,别在循环、判断或者嵌套函数里用,不然会出性能问题,还不好找错。
  • 懒加载组件:有些组件不常用或者加载起来特别慢,就用 React 的懒加载功能。等需要用这个组件的时候再去加载它,这样页面一开始加载得就快多了。
相关推荐
辻戋15 小时前
从零实现React Scheduler调度器
前端·react.js·前端框架
徐同保15 小时前
使用yarn@4.6.0装包,项目是react+vite搭建的,项目无法启动,报错:
前端·react.js·前端框架
Qrun16 小时前
Windows11安装nvm管理node多版本
前端·vscode·react.js·ajax·npm·html5
中国lanwp16 小时前
全局 npm config 与多环境配置
前端·npm·node.js
JELEE.17 小时前
Django登录注册完整代码(图片、邮箱验证、加密)
前端·javascript·后端·python·django·bootstrap·jquery
TeleostNaCl19 小时前
解决 Chrome 无法访问网页但无痕模式下可以访问该网页 的问题
前端·网络·chrome·windows·经验分享
前端大卫21 小时前
为什么 React 中的 key 不能用索引?
前端
你的人类朋友21 小时前
【Node】手动归还主线程控制权:解决 Node.js 阻塞的一个思路
前端·后端·node.js
小李小李不讲道理1 天前
「Ant Design 组件库探索」五:Tabs组件
前端·react.js·ant design
毕设十刻1 天前
基于Vue的学分预警系统98k51(程序 + 源码 + 数据库 + 调试部署 + 开发环境配置),配套论文文档字数达万字以上,文末可获取,系统界面展示置于文末
前端·数据库·vue.js