Source

Frameworks/AsyncTableTools/hooks/useTableState/useTableState.js

import { useCallback } from 'react';
import useDeepCompareEffect from 'use-deep-compare-effect';

import useContextOrInternalStateAndRefs from './hooks/useContextOrInternalStateAndRefs';
import useStateObservers from './hooks/useStateObservers';
import useSerialisers from './hooks/useSerialisers';
import compileState from './helpers/compileState';

/**
 * Provides an interface for hooks to store their states name-spaced into the tableState in the TableContext
 *
 *  @param   {object} namespace            A key to namespace the state under (e.g. 'filters', 'sort')
 *  @param   {object} [initialState]       Initial state to put into the table state
 *  @param   {object} [options]            Options for the state
 *  @param   {object} [options.serialiser] A function to serialise the table state and allow access it via the useSerialisedTableState hook
 *  @param   {object} [options.observers]  An object with properties of an other state namespace and an object or function returning an object with an desired state should the other state change
 *
 *  @returns {Array}                       An array with the first item being the tableState, the second a function to set the state and a third optional item with the serialised state if a serialiser was provided
 *
 *  @category AsyncTableTools
 *  @subcategory Hooks
 *
 */
const useTableState = (namespace, initialState, options = {}) => {
  const {
    serialisers,
    observers,
    state: [state, setState],
  } = useContextOrInternalStateAndRefs();

  useStateObservers(namespace, options.observers, observers);
  useSerialisers(namespace, options.serialiser, serialisers);

  const setTableState = useCallback(
    function setTableState(newStateForNameSpace) {
      return setState((currentState) => {
        const newState =
          typeof newStateForNameSpace === 'function'
            ? newStateForNameSpace(currentState?.tableState?.[namespace])
            : newStateForNameSpace;

        const nextState = compileState(
          namespace,
          currentState,
          newState,
          observers.current,
          serialisers.current
        );

        // Comment out for debugging table issues
        // console.group('State change by', namespace);
        // console.log('New state for namespace', newState);
        // console.log('Current state:', currentState?.tableState);
        // console.log('Next State:', nextState?.tableState);
        // console.groupEnd();

        return nextState;
      });
    },
    [observers, serialisers, setState, namespace]
  );

  useDeepCompareEffect(() => {
    setTableState(initialState);
  }, [initialState, setTableState]);

  return [
    state?.tableState?.[namespace],
    setTableState,
    ...(options.serialiser ? [state?.serialisedTableState?.[namespace]] : []),
  ];
};

export default useTableState;