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}</>
}