react中hooks使用

发布于:2025-04-03 ⋅ 阅读:(11) ⋅ 点赞:(0)

1、react 中的hook是16.8引入的函数,不需要编写组件类。可以理解成是函数式编程。

2、使用的前提:只能在react函数组件中使用或者Hook 中调用 hook,不能在javascript中使用。

一、常用的方法

1、useState

1.1 定义

用于给添加状态的,比如常用的数据请求前先loading,然后请求成功后loading关闭。

cons [demo, setDemo] = useState(1)

// demo设置初始值,在某些条件或者 场景下要改变demo的值
setDemo(22)

2、useRef

2.1 定义

用于访问 DOM 节点或在渲染间保持一个可变的值。

useRef返回的是一个 ref 对象,.current 属性是初始化传入的参数,使用这个更新不会引起当前组件或者子组件的更新。

1、但使用 React.createRef ,每次重新渲染组件都会重新创建 ref。

2、如果使用useState定义值的时候有异步问题,就可以用useRef。


const demo = useRef()

// 如果要给demo中添加值
demo.current={
    name: 'karla',
    year: 18
}

3、useEffect

3.1 定义

用于数据获取、订阅、请求数据

  • useEffect 不能瞎更新,如果监听某个值,这个值一直变化,就会进入死循环,临时状态可以用useRef 来存储,避免不必要的更新
  • useEffect
useEffect(() => {
  // 副作用代码
  return () => {
    // 清理操作
  };
}, [dependency]); // 依赖项数组,用于指定何时重新运行副作用

3.2 请求接口


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

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

    // 使用 useEffect 进行数据获取
    useEffect(() => {
        // 模拟一个异步的数据获取操作
        const fetchData = async () => {
            const response = await fetch('XXXXXXXXXXXX');
            // 将获取到的数据更新到 data state 中
            setData(response );
        };

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

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

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

export default Index;

3.3 调用异步写法

import { useEffect, useRef } from 'react';
const approveStatusList = useRef([])

/** 写法一 */
useEffect(() => {
    const fetch = async () => {
    /** 获取接口 */
    const res = await getList()
    approveStatusList.current = res|| [];
  };
  fetch();
}, []);


/** 写法二 */
useEffect(() => {
  (async function() {
    const res = await getList()
    approveStatusList.current = res|| [];
  })();
}, []);

3.4 监听某个值

    useEffect(() => {
      const params = {
        tabsList
      };
      handleParams(params);
    }, [tabsList]);

4、useCallback

4.1 定义

用于优化性能,避免在组件重新渲染时不必要的函数重建

在react 中,重新渲染时,内部定义的函数都会重新创建,可能会导致:

1、不必要的子组件重新渲染(当函数作为 props 传递给子组件)

2、依赖该函数的 useEffect 被 不必要的触发

使用场景
1、函数作为 props 传递给子组件(特别是用 React.memo 优化的子组件)

2、函数作为其他 Hook 的依赖项(如 useEffect、useMemo 等)

3、在自定义 Hook 中返回稳定的函数引用

注意事项
1、不要过度使用 useCallback - 只有在确实需要优化性能时才使用

2、正确设置依赖项 - 遗漏依赖项会导致闭包问题

3、useCallback 不会使函数运行更快 - 它只是避免不必要的重新创建

const memoizedCallback = useCallback(
  () => {
    // 函数逻辑
  },
  [dependencies] // 依赖项数组
);

4.1 基础示例

4.1.1 计数器示例

带 useCallback

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

function Counter() {
  const [count, setCount] = useState(0);
  
  // 使用 useCallback 缓存函数
  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, []); // 空依赖数组表示函数不会改变

  const decrement = useCallback(() => {
    setCount(c => c - 1);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}
4.1.2 与子组件配合使用
import React, { useState, useCallback } from 'react';

// 子组件(使用 React.memo 优化)
const Button = React.memo(({ onClick, children }) => {
  console.log(`Button ${children} rendered`);
  return <button onClick={onClick}>{children}</button>;
});

function ParentComponent() {
  const [count, setCount] = useState(0);
  const [value, setValue] = useState('');

  // 使用 useCallback 缓存函数
  const increment = useCallback(() => {
    setCount(c => c + 1);
  }, []);

  return (
    <div>
      <p>Count: {count}</p>
      <Button onClick={increment}>Increment</Button>
      
      <input 
        value={value}
        onChange={(e) => setValue(e.target.value)}
      />
    </div>
  );
}

在这个例子中,即使 ParentComponent 因为 value 状态变化而重新渲染,increment 函数也不会重新创建,因此 Button 组件不会不必要地重新渲染。

5、useMemo

5.1 定义

对一个计算过程进行记忆化,只有当依赖项改变时才会重新计算。

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

6、useImperativeHandle

6.1 定义

用于在使用 forwardRef 时自定义暴露给父组件的实例值。

useImperativeHandle(ref, handle)

  • ref:父组件传递的引用。
  • handler:返回一个对象,定义要暴露给父组件的实例值。
useImperativeHandle(ref, () => ({
  focusMyInput: () => {
    myRef.current.focus();
  }
}));

6.2 场景使用

情景:子组件的table中数据更新出暴露出来给父级,父亲能接收到这个更新后的数据,父级中定义ref,然后获取子级更新的数据。

/** 父组件 **/
import { useRef, useState } from "react";
import CoverModel from "./coverModel";

const Index = (props, ref) => {
  const coverModelRef = useRef<any>(null); // 客户团覆盖机型

  const handleSave = () => {
    // 获取子组件中的
    console.log(coverModelRef?.current?.table);
  };

  return (
    <>
      <CoverModel ref={coverModelRef} />
    </>
  );
};

export default Index;

/** 子组件 */
import React, {
  forwardRef,
  useImperativeHandle,
  useMemo,
  useState,
} from "react";
import { observer } from "mobx-react";
import {Button, DataSet, Table} from 'choerodon-ui/pro';

const Index = observer(
  forwardRef((props: any, ref: any) => {
    useImperativeHandle(ref, () => {
      return {
        table: tableDs.toData(),
      };
    });

    /** table ds */
    const tableDs = useMemo(
      () =>
        new DataSet({
          ...tableList(id),
          events: {
            load: () => {
              // 数据加载完成后更新 ref,父级中会接收到
              if (ref) {
                ref.current = {
                  table: tableDs.toData(),
                };
              }
            },
          },
        }),
      [id]
    );
    const columns = useMemo(() => {
      return [
        { name: "name" },
        { name: "code" },
        { name: "manageIndustryName" },
      ];
    }, []);

    return (
      <>
        <Table
          dataSet={tableDs}
          columns={columns}
          buttons={tableButtons}
          pagination={false}
          style={{ marginBottom: "16px" }}
          renderEmpty={() => {
            return <div>暂无数据</div>;
          }}
        />
      </>
    );
  })
);

export default Index;

7、useContext

7.1 定义

8、useReducer

8.1 定义

9、useLayoutEffect

9.1 定义

其功能与 useEffect 相同,但它会在所有的 DOM 变更之后同步调用,可以用于读取 DOM 布局并同步触发重渲染。在浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。

useLayoutEffect(() => {
  // 读取 DOM 布局并同步触发重渲染的代码
  return () => {
    // 清理操作
  };
}, [dependency]); // 依赖项数组,用于指定何时重新运行副作用

10、useDebugValue

用于在 React DevTools 中显示自定义 Hook 的标签。这个 Hook 通常不直接使用在生产代码中,主要用于调试。

useDebugValue(value); // 在 DevTools 中显示 value 的值或标签。