react-singleton-hook icon indicating copy to clipboard operation
react-singleton-hook copied to clipboard

react-singleton-hook + use-context-selector

Open rnarcos opened this issue 4 years ago • 1 comments

I have a utilty function that creates a Context.Provider, and a useContext.

For my specific case, I'd like to use use-context-selector library to improve the performance of my application.

The API for the use-context-selector is: const myContextData = useContextSelector(Context, (state) => state[0].data); In my function, I create an abstraction for the useContextSelector, like this: (contextSelectorFn) => useContextSelector(Context, contextSelectorFn).

This way, I can use my custom hook directly like: const myUserId = useUserData((state) => state[0].id);. I'm sort of having a hard time understand how could I simply adhere to this singleton pattern for this use case.

Here's the code for my utility function as of now:

import type { Dispatch, ReactElement, ReactNode, SetStateAction } from 'react';
import { useState } from 'react';
import { createContext, useContextSelector } from 'use-context-selector';

type GlobalState<State> = [State, Dispatch<SetStateAction<State>>];
type Provider = (props: { children: ReactNode }) => ReactElement;
type GlobalContext<State> = <Selected>(
  selector: (value: GlobalState<State>) => Selected,
) => Selected;

function createGlobalStateContext<State>(
  initialState: State,
): [GlobalContext<State>, Provider] {
  const Context = createContext<GlobalState<State>>([initialState, () => {}]);

  const ProviderComponent: Provider = ({ children }) => {
    const [state, setState] = useState<State>(initialState);

    const contextState: GlobalState<State> = [state, setState];

    return <Context.Provider value={contextState}>{children}</Context.Provider>;
  };

  return [
    (contextSelectorFn) => useContextSelector(Context, contextSelectorFn),
    ProviderComponent,
  ];
}

rnarcos avatar Dec 28 '21 20:12 rnarcos

Hi @rnarcos, underlying state change always causes a component to rerender. I'll take a look at the library you are using and try to incorporate something similar when have time.

I've actually thought about another kind of optimization, used by swr: you can just

const { id } = useUserData(); 

and the component will only update when id has changed, not any other field. will this work for you?

Light-Keeper avatar Jan 04 '22 12:01 Light-Keeper