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 的值或标签。