ahooks

repository·master·Indexed 12 days ago

https://github.com/alibaba/hooks

A high-quality and reliable React Hooks library containing a comprehensive collection of basic and advanced hooks refined from real-world business scenarios. It features stable output references and latest input execution to mitigate common closure problems, and includes utilities like useMemoizedFn and useUrlState.

Tokens
112.1K
Snippets
382
Records
539
Agent score
93%

What's inside ahooks

  1. Overview of ahooks features

    master

    ahooks is a high-quality, reliable React Hooks library designed to simplify React development. Key features include:

    • Easy to learn and use: Designed for developer productivity.
    • SSR Support: Compatible with Server-Side Rendering environments.
    • Robustness: Special handling for input/output functions to avoid common closure issues.
    • Comprehensive Library: Includes a wide range of both basic hooks and advanced hooks extracted from real-world business logic.
    • TypeScript Support: Built with TypeScript, providing full type definitions for a better developer experience.
  2. Key features of ahooks

    master

    ahooks is a high-quality, reliable React Hooks library with the following characteristics:

    • Easy to learn and use
    • SSR Support: Compatible with Server-Side Rendering.
    • Closure Safety: Special handling for input and output functions to avoid common closure issues.
    • Rich Hook Selection: Includes a large number of advanced hooks extracted from real-world business logic, as well as a variety of fundamental hooks.
    • TypeScript Support: Built with TypeScript, providing complete type definitions.
  3. What is react-refresh (HMR)?

    master

    React-refresh (via react-refresh-webpack-plugin) is a Hot Module Replacement (HMR) plugin for React. It enables "Fast Refresh," allowing developers to edit code and see changes in the browser without losing the component's current state.

    In frameworks like umi, you can enable this feature by configuring fastRefresh: {} in your settings.

  4. Use useEventEmitter for cross-component event notifications

    master

    The useEventEmitter hook provides an EventEmitter instance that can be shared across multiple components via props or Context. This is particularly useful for notifying components that are far apart in the component tree or for sharing events among many components simultaneously.

    Key Behaviors:

    • Stability: The EventEmitter instance remains the same across multiple re-renders of the component that calls the hook.
    • Automatic Cleanup: When using useSubscription, the subscription is automatically registered when the component is created and automatically unsubscribed when the component is destroyed.

    When to use it:

    • Use useEventEmitter for distant components or complex many-to-many event sharing.
    • Use props (passing an onEvent callback) for direct child-to-parent communication.
    • Use forwardRef for direct parent-to-child method calls.
    // 1. Create the emitter in a parent or provider
    const event$ = useEventEmitter();
    
    // 2. Share event$ via props or Context...
    
    // 3. In a distant component, emit an event
    event$.emit('event-name');
    
    // 4. In another component, subscribe to the event
    event$.useSubscription(val => {
      console.log(val);
    });
  5. Update data immediately with mutate

    master

    The mutate function allows you to modify the data state immediately, similar to React.setState. This is useful for 'optimistic updates' where you want to provide instant UI feedback before the background request completes.

    Supported patterns:

    • mutate(newData)
    • mutate((oldData) => newData)
    // Example: Optimistic update
    mutate(newData);
    // Then call the actual service in the background
    run();
  6. Behavioral notes for throttled useRequest

    master

    When using throttle mode in useRequest, keep the following behaviors in mind:

    • runAsync Return Value: runAsync returns a Promise only when the request is actually executed. If the call is suppressed by the throttle mechanism, it will not return a value.
    • cancel Functionality: The cancel method can be used to abort a function that is currently waiting to be executed due to the throttle delay.
  7. How useDrop and useDrag work together

    master

    The useDrop and useDrag hooks are a pair designed to manage data transfer during drag-and-drop operations.

    • useDrag: Should be used in conjunction with useDrop to initiate a drag operation. It attaches drag behavior to a target element.
    • useDrop: Can be used alone to accept dropped content (files, text, or URIs) or pasted content. It attaches drop behavior to a target element.

    Note that useDrop also treats content pasted into the drop area as a drop event.

  8. Use useRafTimeout to simulate setTimeout with requestAnimationFrame

    master

    The useRafTimeout hook provides a way to implement setTimeout functionality using requestAnimationFrame. This ensures that the callback function is only executed when the page is active and rendering. If the page is hidden or minimized, the execution is paused, which can improve performance and prevent unnecessary background processing.

    In Node.js environments, requestAnimationFrame will automatically degrade to setTimeout.

  9. How to provide a target to DOM-based Hooks

    master

    Most DOM-based Hooks in ahooks require a target parameter, which specifies the element to be processed. The target parameter supports three different types of input:

    1. React.MutableRefObject: Pass a ref created via useRef.
    2. HTMLElement: Pass a direct reference to a DOM element (e.g., via document.getElementById).
    3. () => HTMLElement: Pass a function that returns an element. This pattern is recommended for SSR (Server-Side Rendering) scenarios to ensure the DOM is accessed only after mounting.

    Additionally, the target in DOM-based Hooks is dynamic. You can pass conditional logic (e.g., using a state variable to switch between different refs) and the Hook will react to the change.

    // 1. Using React.MutableRefObject
    const ref = useRef(null);
    const isHovering = useHover(ref);
    
    // 2. Using HTMLElement
    const isHovering = useHover(document.getElementById("test"));
    
    // 3. Using a function (Recommended for SSR)
    const isHovering = useHover(() => document.getElementById("test"));
    
    // 4. Using a dynamic target
    const [boolean, { toggle }] = useBoolean();
    const ref1 = useRef(null);
    const ref2 = useRef(null);
    const isHovering = useHover(boolean ? ref1 : ref2);
  10. Understand React Hooks & react-refresh (HMR) behavior

    master

    The react-refresh-webpack-plugin enables "Fast Refresh" (HMR) for React components. In development, it allows you to edit code while maintaining the current component state.

    Core Mechanism

    • Class Components: Always remount, causing existing state to be reset.
    • Function Components: Designed to preserve existing state (e.g., useState, useRef).
    • Hooks Lifecycle during HMR:
      • useState and useRef values do not update to maintain state.
      • useEffect, useCallback, and useMemo do re-execute to clean up old effects (holding stale values) and set up new ones with updated values.

    This discrepancy between state preservation and effect re-execution can lead to unexpected behaviors in custom hooks.

  11. How ahooks handles closures and function references

    master

    ahooks is designed to mitigate common React closure problems by applying two specific behaviors to its hooks:

    1. Stable Output References: All functions returned by ahooks hooks (e.g., setState-like functions) have stable references. They will not change between renders, meaning you do not need to include them in the dependency arrays of useEffect, useCallback, or useMemo.

    2. Latest Input Execution: For functions passed as arguments to ahooks hooks (user input functions), ahooks ensures that the version of the function executed is always the latest one from the current render. This prevents the "stale closure" problem where a function captures old state or props.

    This behavior allows you to pass functions that depend on current state into hooks like useInterval without manually managing dependency arrays or worrying about stale values.

    // Example: useInterval always sees the latest state
    const [state, setState] = useState();
    
    useInterval(() => {
      console.log(state); // 'state' will always be the most recent value
    }, 1000);