import { useState, useRef, useEffect, RefObject } from "react"; import { isEqual } from "underscore"; import update, { Spec } from "immutability-helper"; import { useAsyncEffect } from "use-async-effect"; import { Component } from "react"; // Re-export useAsyncEffect export { useAsyncEffect }; export function useImmutableState(v: S): [S, (spec: Spec) => void] { /** useState wrapper hook that requires updating using an "immutability-helper" spec */ const [state, setState] = useState(v); const updateState = function (cset: Spec) { const newState = update(state, cset); return setState(newState); }; return [state, updateState]; } export function useMemoizedValue( obj: any, equalityFunction: (a: any, b: any) => boolean = isEqual, ) { /** Hook to keep a dependency up to date using a deep equals approach */ const ref = useRef(obj); if (obj == ref.current || equalityFunction(obj, ref.current)) { return ref.current; } else { ref.current = obj; return obj; } } export class StatefulComponent extends Component { constructor(props: Props) { console.warn( "StatefulComponent is deprecated. Use useImmutableState instead.", ); super(props); this.updateState.bind(this); } updateState(spec: Spec) { const newState = update(this.state, spec); this.setState(newState); } } export function usePrevious(value: T) { const ref: RefObject = useRef(undefined); useEffect(() => { ref.current = value; }); return ref.current; } export function useAsyncMemo(fn: () => Promise, deps: any[]): T | null { const [value, setValue] = useState(null); useAsyncEffect(async () => { const result = await fn(); setValue(result); }, deps); return value; }