hooks_use-route-handler.js

import { React, ReactRouter } from '@gravityforms/libraries';

const { useEffect, useRef, useState } = React;
const { useSearchParams } = ReactRouter;

/**
 * @module useRouteHandler
 * @description A hook that handles route changes.
 *
 * @since 4.2.0
 *
 * @return {object} The route handler state and actions.
 */
const useRouteHandler = () => {
	const [ routeHandlerIds, setRouteHandlerIds ] = useState( [] );
	const [ routeHandlers, setRouteHandlers ] = useState( {} );
	const [ searchParams, setSearchParams ] = useSearchParams();
	const prevSearchParams = useRef( searchParams );
	const isNavigating = useRef( false );

	/**
	 * @function addRouteHandler
	 * @description Add a route handler.
	 *
	 * @since 4.2.0
	 *
	 * @param {string}   id      The id of the route handler.
	 * @param {Function} handler The handler function.
	 *
	 */
	const addRouteHandler = ( id, handler ) => {
		if ( ! id || ! handler ) {
			return;
		}
		if ( routeHandlerIds.includes( id ) ) {
			return;
		}
		setRouteHandlers( {
			...routeHandlers,
			[ id ]: handler,
		} );
		setRouteHandlerIds( [ ...routeHandlerIds, id ] );
	};

	/**
	 * @function removeRouteHandler
	 * @description Remove a route handler.
	 *
	 * @since 4.2.0
	 *
	 * @param {string} id The id of the route handler.
	 *
	 */
	const removeRouteHandler = ( id ) => {
		if ( ! id ) {
			return;
		}
		setRouteHandlers( {
			...routeHandlers,
			[ id ]: undefined,
		} );
		setRouteHandlerIds( routeHandlerIds.filter( ( handlerId ) => handlerId !== id ) );
	};

	/**
	 * @function setRoute
	 * @description Set the route. Sets isNavigating to true to prevent the routeHandlers from running.
	 *
	 * @since 4.2.0
	 *
	 * @param {object} params  The params to set.
	 * @param {object} options The options to set.
	 *
	 */
	const setRoute = ( params, options = {} ) => {
		isNavigating.current = true;
		setSearchParams( params, options );
	};

	useEffect( () => {
		if ( isNavigating.current ) {
			isNavigating.current = false;
			return;
		}
		// Loop through all the route handlers and call them.
		routeHandlerIds.forEach( ( id ) => {
			const handler = routeHandlers[ id ];
			if ( ! handler ) {
				return;
			}
			handler( {
				searchParams,
				prevSearchParams: prevSearchParams.current,
			} );
		} );
		prevSearchParams.current = searchParams;
	}, [ searchParams ] );

	return {
		addRouteHandler,
		removeRouteHandler,
		setRoute,
		searchParams,
		setSearchParams,
	};
};

export default useRouteHandler;