Categories
Programming React User Interface

React – UseLocationState hook

This hook, made in typescript, can be used to change the current location state. Just use it as you would use the useState hook.

import { useHistory } from "react-router-dom";
import { useCallback } from "react";

//callback definition.
type SetStateType<T> = ((prevState: T) => T) | T;

export default <T extends any>(defaultState: T)
    : [T, (newState: SetStateType<T>) => void] => {

    const { replace, location: { state } } = useHistory<T>(); 
    const currentState = isNullOrUndefined(state) ? defaultState : state;

    const setState = useCallback((newState: SetStateType<T>) => {
        const state = (newState instanceof Function)
            ? newState(currentState)
            : newState;
        state !== currentState && replace({ state });
    }, [replace, currentState]);

 return [currentState, setState];
}

UPDATE Jan 2022: Simplified version using useState():

import { useHistory } from "react-router-dom";
import { useEffect, useState } from "react";

//callback definition.
type SetStateType<T> = ((prevState: T) => T) | T;

const useLocationState = <T extends any>(defaultState: T)
    : [T, (newState: SetStateType<T>) => void] => {

    const { replace, location } = useHistory<T>();
    const [state, setState] = useState<T>(location.state || defaultState);

    //save state in locationState
    useEffect(() => {
        location.state !== state && replace({ state });        
    }, [replace, state, location.state])

    return [state, setState];
}

export default useLocationState;

Example:

import * as React from 'react';
import useLocationState from '../UseLocationState';

export default (() => {
    const [someState, setSomeState] = useLocationState({ test: 1 });

    //change location state (2 options)
    useEffect(() => {
        //option 1
        setSomeState({ test: 10 });
        //option 2
        setSomeState(prev => ({ test: prev.test - 5 })) ;
    }, [setSomeState]);

    return <>{someState}</>
}