Home > database >  React Hooks - Global state without context
React Hooks - Global state without context

Time:11-02

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

CodePudding user response:

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.

CodePudding user response:

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