React Hooks - Global state without context

Viewed 334

I am implementing a hook "useUserPosts", which is supposed to be used in several routes of my application.

As I already have a context "PostsContext" which re-renders my Cards when data changes (totalLikes, totalComments, descriptions, ...), I have decided to avoid creating another one called "UserPostsContext" which purpose is to return the user posts array.

I know, why not to use the PostsContext instead?...

The answer is that, in PostsContext, to avoid performance issues, I am storing a map (key, value), in order to get/update the posts dynamic data in O(1), something which is only useful in my components (so, it is used to synchronize Cards basically)

Is it possible/a common practice in React to create hooks that handles global states without using the Context API or Redux?

I mean, something like

// Global State Hook
const useUserPosts = (() => {
   const [posts, setPosts] = useState({});
   return ((userId) => [posts[id] ?? [], setPosts]);
})();


// Using the Global State Hook
function useFetchUserPosts(userId) {
   const [posts, setPosts] = useUserPosts(userId);
   const [loading, setLoading] = useState(!posts.length);
   const [error, setError] = useState(undefined);

   const cursor = useRef(new Date());
   const hasMoreToLoad = useRef(false);
   const isFirstFetch = useRef(true);

   const getUserPosts = async () => {
      // ...
   }

   return { posts, loading, error, getUserPosts };
}

Note: my purpose with this is to:

1. Reproduce some kind of cache
2. Synchronize the fetched data of each stack screen that is mounted in order to reduce backend costs
3. Synchronize user posts deletions
2 Answers

Even if I think creating a new global state is the best solution, if you really want to avoid it, you could create your own as follow :

export class AppState {
  private static _instance: AppState;


  public state = new BehaviorSubject<AppStateType>({});

  /**
   * Set app state without erasing the previous values (values not available in the newState param)
   * */
  public setAppState = (newState: AppStateType) => {
    this.state.next({ ...this.state, ...newState });
  };

  private constructor() {}

  public static getInstance(): AppState {
    if (!AppState._instance) {
      AppState._instance = new AppState();
    }

    return AppState._instance;
  }
}

With this kind of type :

export type AppStateType = {
  username?: string;
  isThingOk?: boolean;
  arrayOfThing?: Array<MyType>;
...
}

And use it this way :

const appState = AppState.getInstance();
...
...
appState.setAppState({ isThingOk: data });
...
...
appState.state.subscribe((state: AppStateType) => {// do your thing here});

Not sure this is the best way to create a state of your own but it works pretty well. Feel free to adapt it to your needs.

I can recommand you to use some light state management library as zustand: https://github.com/pmndrs/zustand.

You can with this library avoid re-render and specify to re-render just want the data you want change or change in certain way with some function to compare old and new value.

Related