ProComponents provides a comprehensive set of React hooks to handle common patterns like debouncing, deep comparison, data fetching, and reference management.
State Management Hooks
useDebounceFn
A hook that debounces function execution, useful for optimizing expensive operations.
import { useDebounceFn } from '@ant-design/pro-components';
const MyComponent = () => {
const { run, cancel } = useDebounceFn(async (value: string) => {
await searchAPI(value);
}, 300);
return (
<input
onChange={(e) => run(e.target.value)}
onBlur={cancel}
/>
);
};
fn
(...args: T) => Promise<any>
required
The async function to debounce
Debounce delay in milliseconds. If 0 or undefined, executes immediately
run
(...args: T) => Promise<U | undefined>
Debounced function that returns a promise
Cancels the pending debounced function execution
useDebounceValue
Debounces state updates to reduce re-render frequency.
import { useDebounceValue } from '@ant-design/pro-components';
const SearchInput = () => {
const [searchText, setSearchText] = useState('');
const debouncedSearchText = useDebounceValue(searchText, 300);
useEffect(() => {
// Only runs after 300ms of no changes
performSearch(debouncedSearchText);
}, [debouncedSearchText]);
return <input value={searchText} onChange={e => setSearchText(e.target.value)} />;
};
Debounce delay in milliseconds
Optional dependency list for custom control
useLatest
Returns a ref that always contains the latest value, useful for callbacks.
import { useLatest } from '@ant-design/pro-components';
const MyComponent = ({ onSave }) => {
const onSaveRef = useLatest(onSave);
useEffect(() => {
const timer = setInterval(() => {
// Always calls the latest onSave
onSaveRef.current();
}, 1000);
return () => clearInterval(timer);
}, []); // Empty deps - no re-subscription needed
};
A ref object containing the latest value
usePrevious
Returns the previous value of a state or prop.
import { usePrevious } from '@ant-design/pro-components';
const Counter = ({ count }) => {
const prevCount = usePrevious(count);
return (
<div>
<p>Current: {count}</p>
<p>Previous: {prevCount}</p>
</div>
);
};
The previous state value (undefined on first render)
useRefFunction
Creates a stable function reference that always calls the latest version.
import { useRefFunction } from '@ant-design/pro-components';
const MyComponent = ({ onClick }) => {
const handleClick = useRefFunction(onClick);
// handleClick identity never changes, but always calls latest onClick
useEffect(() => {
document.addEventListener('click', handleClick);
return () => document.removeEventListener('click', handleClick);
}, []); // Safe to use empty deps
};
fn
T extends (...args: any) => any
required
The function to wrap
stableFunction
(...args: Parameters<T>) => ReturnType<T>
A stable function reference that always executes the latest version
useReactiveRef
A ref that triggers re-renders when its value changes.
import { useReactiveRef } from '@ant-design/pro-components';
const MyComponent = () => {
const countRef = useReactiveRef(0);
const increment = () => {
countRef.current += 1; // Triggers re-render
};
return (
<div>
<p>Count: {countRef.current}</p>
<button onClick={increment}>Increment</button>
</div>
);
};
Initial value for the ref
A ref that triggers re-renders when changed
useRefCallback
Creates a ref with a callback that fires when the ref value changes.
callback
(currentRef: MutableRefObject<T>) => void
required
Callback function executed when ref changes
Initial value for the ref
A ref object that calls the callback on changes
Deep Comparison Hooks
useDeepCompareEffect
Like useEffect, but uses deep comparison for dependencies.
import { useDeepCompareEffect } from '@ant-design/pro-components';
const MyComponent = ({ filters }) => {
useDeepCompareEffect(() => {
fetchData(filters);
}, [filters]); // Deep compares filters object
return <DataTable />;
};
effect
React.EffectCallback
required
Effect function to execute
Dependency array (compared deeply)
Keys to ignore during deep comparison
useDeepCompareEffectDebounce
Combines deep comparison with debouncing for effect execution.
import { useDeepCompareEffectDebounce } from '@ant-design/pro-components';
const SearchComponent = ({ filters }) => {
useDeepCompareEffectDebounce(
() => {
searchAPI(filters);
},
[filters],
undefined,
300 // 300ms debounce
);
return <Results />;
};
effect
React.EffectCallback
required
Effect function to execute
Dependency array (compared deeply)
Keys to ignore during comparison
Debounce delay in milliseconds
useDeepCompareMemo
Like useMemo, but uses deep comparison for dependencies.
import useDeepCompareMemo from '@ant-design/pro-components';
const MyComponent = ({ items }) => {
const processedItems = useDeepCompareMemo(
() => expensiveProcessing(items),
[items]
);
return <List data={processedItems} />;
};
Function that computes the memoized value
dependencies
React.DependencyList
required
Dependency array (compared deeply)
Data Fetching Hooks
useFetchData
Manages data fetching with automatic caching and loading states.
import { useFetchData } from '@ant-design/pro-components';
const UserList = ({ userId }) => {
const [data, loading] = useFetchData({
proFieldKey: userId,
params: { id: userId },
request: async (params) => {
const response = await fetch(`/api/users/${params.id}`);
return response.json();
},
});
if (loading) return <Spin />;
return <div>{data?.name}</div>;
};
Configuration object for data fetching
Async function that fetches the datatype ProRequestData<T, U> = (params: U, signal: any) => Promise<T>
Parameters passed to the request function
Cache key for the request
Whether the request is currently loading
Editable Table Hooks
useEditableArray
Manages editable state for table rows with array-based data sources.
import { useEditableArray } from '@ant-design/pro-components';
const EditableTable = () => {
const [dataSource, setDataSource] = useState([]);
const editable = useEditableArray({
dataSource,
setDataSource,
getRowKey: (row) => row.id,
childrenColumnName: 'children',
onSave: async (key, row, originRow) => {
await saveToAPI(row);
},
onDelete: async (key, row) => {
await deleteFromAPI(key);
},
});
return (
<ProTable
dataSource={dataSource}
editable={editable}
/>
);
};
setDataSource
(dataSource: RecordType[]) => void
required
Function to update the data source
getRowKey
GetRowKey<RecordType>
required
Function to get unique key for each row
Name of the children property for nested data
type
'single' | 'multiple'
default:"'single'"
Whether to allow editing single or multiple rows
Controlled editable row keys
onChange
(editableKeys: React.Key[], editableRows: RecordType[]) => void
Callback when editable keys change
onSave
(key: RecordKey, record: RecordType, originRow: RecordType) => Promise<any>
Callback when a row is saved
onCancel
(key: RecordKey, record: RecordType, originRow: RecordType) => Promise<any>
Callback when editing is cancelled
onDelete
(key: RecordKey, row: RecordType) => Promise<any>
Callback when a row is deleted
Current editable row keys
setEditableRowKeys
(keys: React.Key[]) => void
Function to update editable keys
isEditable
(row: RecordType) => { recordKey: string, isEditable: boolean }
Function to check if a row is editable
startEditable
(recordKey: React.Key, record?: RecordType) => boolean
Function to start editing a row
cancelEditable
(recordKey: RecordKey) => Promise<boolean>
Function to cancel editing a row
saveEditable
(recordKey: RecordKey) => Promise<boolean>
Function to save an edited row
addEditRecord
(row: RecordType, options?: AddLineOptions) => boolean
Function to add a new editable row
actionRender
(row: RecordType) => React.ReactNode[]
Function to render action buttons (save, delete, cancel)
useEditableMap
Manages editable state for map-based data sources.
import { useEditableMap } from '@ant-design/pro-components';
const EditableForm = () => {
const [dataSource, setDataSource] = useState({});
const editable = useEditableMap({
dataSource,
setDataSource,
onSave: async (key, row, originRow) => {
await saveToAPI(row);
},
});
return <ProDescriptions editable={editable} />;
};
setDataSource
(dataSource: RecordType) => void
required
Function to update the data source
type
'single' | 'multiple'
default:"'single'"
Whether to allow editing single or multiple fields
Controlled editable field keys
onSave
(key: RecordKey, record: RecordType, originRow: RecordType) => Promise<any>
Callback when a field is saved
onCancel
(key: RecordKey, record: RecordType, originRow: RecordType) => Promise<any>
Callback when editing is cancelled
Current editable field keys
setEditableRowKeys
(keys: React.Key[]) => void
Function to update editable keys
isEditable
(recordKey: RecordKey) => boolean
Function to check if a field is editable
startEditable
(recordKey: RecordKey, recordValue?: any) => boolean
Function to start editing a field
cancelEditable
(recordKey: RecordKey) => boolean
Function to cancel editing a field
actionRender
(key: RecordKey, config?: ActionTypeText) => React.ReactNode[]
Function to render action buttons
Responsive Hooks
useBreakpoint
Returns the current responsive breakpoint based on screen size.
import { useBreakpoint } from '@ant-design/pro-components';
const ResponsiveComponent = () => {
const breakpoint = useBreakpoint();
return (
<div>
<p>Current breakpoint: {breakpoint}</p>
{breakpoint === 'xs' && <MobileView />}
{breakpoint === 'lg' && <DesktopView />}
</div>
);
};
breakpoint
'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl' | undefined
Current screen breakpoint
xs: < 576px
sm: 576px - 768px
md: 768px - 992px
lg: 992px - 1200px
xl: 1200px - 1600px
xxl: > 1600px
Other Hooks
useDocumentTitle
Sets the document title based on page info.
import { useDocumentTitle } from '@ant-design/pro-components';
const MyPage = () => {
useDocumentTitle(
{
title: 'User Profile',
id: 'user-profile',
pageName: 'Profile',
},
'My App'
);
return <div>Page Content</div>;
};
Object containing title information
Default application title