大白话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 的懒加载功能。等需要用这个组件的时候再去加载它,这样页面一开始加载得就快多了。
相关推荐
web150854159355 分钟前
Nginx 配置前端后端服务
运维·前端·nginx
AC-PEACE6 分钟前
JSX基础 —— 识别JS表达式
开发语言·javascript·react.js
BillKu7 分钟前
Element Plus中el-select选择器的下拉选项列表的样式设置
前端·javascript·vue.js
我家媳妇儿萌哒哒9 分钟前
el-table fixed滚动条被遮挡导致滚动条无法拖动
前端·javascript·vue.js
青春_strive28 分钟前
HTML操作详解
前端·html
小华同学ai42 分钟前
1.3K star!VisActor团队开源神器,3秒生成商业级图表,程序员直呼真香!
前端·github
Mrzheng1681 小时前
前端或者后端通常用到数组使用方式
前端
木亦Sam1 小时前
JavaScript 事件循环机制深度解析:为何你的代码执行顺序和预期不同?
前端·javascript
海绵波波1071 小时前
vue写一个登录页面
javascript·vue.js·ecmascript
郡nionio1 小时前
js的原型、原型链
javascript·面试