Real-Dev-Squad / mobile-app

The main app for our organization
MIT License
12 stars 30 forks source link

[RFC] State management #125

Open ankushdharkar opened 2 years ago

shreya-mishra commented 2 years ago

@sakshambhatt assigned to you!

sakshambhatt commented 2 years ago

I am half way done with the RFC. Do we have a wiki page or notion where I can put it?

shreya-mishra commented 2 years ago

I am half way done with the RFC. Do we have a wiki page or notion where I can put it?

put here itself

sakshambhatt commented 2 years ago

RFC no: 1 Start Date: 13th July 2022

State management in RDS RN mobile app

Table of contents

List of approvers:

  1. Ankush Dharkar
  2. Shreya Mishra

Abstract (what is this about?):

About managing all state effectively in the React Native app, in such a manner that performance and DX are good without it needing to be over-engineered. What is state? Data that can mutate over time and needs to be stored in app. There are two kinds of state, server cache (data being stored in DB but also being stored in UI for better UX) and UI state (data which is stored and used only in the UI, theme, isLoading, isConfirmModalOpen, etc.).

Proposed solutions:

Argument 1:

  1. No need for external state management. Memoized useContext + React-Query for the win! reference: Kent c Dodds blog
  2. UI state problem? Lift State up -> Component composition -> Context (Don't put all providers at global level, put them where they are needed).
  3. Server cache: React Query or SWR.
  4. Since Remix has arrived, Kent is promoting Remix, which can not be used with mobile app.
  5. Pros: No need for external library. Since there is a process to be followed for solving the state problem, there is less chance that people will put everything in global state which can happen when external library is used.
  6. Cons: Bad DX, lots of boilerplate, chances of error, component can't subscribe to subset of state (partially solved by using multiple ContextProviders and wrapping only the components which need them).
  7. This can go wrong if the state changes too often (live price graph) reference: Dominik React Query maintainer

Argument 2:

  1. useContext for Dependency Injection but not for state value propogation reference.
  2. When to not use Context.
  3. Basically, useContext can be used for Theme, AuthContext, etc. reference. But for state which might be updated frequently and, or if a component only wants to subscribe to a subset of the state, then probably go with Redux or Zustand. reference
  4. Redux tried to useContext in v6 for state value propogation and it caused performance issues. Now, they are only using useContext for passing a static copy of state. reference
  5. UI state problem? Lift state up -> Component composition -> Context if the state is not changing as much (loggedInUserData, theme) else go with Redux or zustand.
  6. Pros: Less chances of error, less chances of going wrong, better DX.
  7. Cons: Possibility of putting everything in global store when not needed, learning redux/ zustand.

Handling server cache:

Options:

  1. React Query: For component scoped server cache and for global as well if zustand is used.
  2. SWR: Similar to React query but minimal.
  3. Custom hooks which do the same thing: DIY.
  4. Redux thunk/ sagas/ RTK query: if redux is used for server cache that is supposed to goto global store.

Problems to solve:

  1. In either case, if the server cache is actually maintained as cache in the app. Then we will need to also maintain when any particular data becomes stale and how to fetch it.
  2. We may also face a scenario where fetching data between render might trigger another render. Or the scenario where in future we use suspense along with above data fetching and caching solutions.

React Query v SWR:

  1. React Query has a bundle size of 50kB vs 15kB of SWR
  2. React Query has mutation hook for server side effects (post, put, patch)
  3. All of the data that is cached is garbage collected if any query remains inactive for 5 minutes in React Query.
  4. querying, caching, polling, parallel querying, initial data, window-focus re-fetching, network status re-fetching are common in both

UI & UX:

There won't be any changes in the UI. UX however, will be consistently good due to lower chance of performance issues.

Architecture changes:

Whatever option is selected must be enforced by maintainers and reviewers in order to maintain consistency and sanity. Also, new developers must be introduced to the particular pattern we decide to follow.

  1. For the fist solution multiple ContextProviders will be created and wrapped around colocated and composite components.
  2. For the second solution, there will be ContextProviders for value that seldom changes, and either selectors (redux) or useStore hooks in case of Zustand.
  3. For both the solutions, all the data fetching will be done via hooks (useQuery-ReactQuery, useSWR-SWR, useCustomQuery-DIY hook), and not via useEffect + useState in the component.

Library dependencies

React Query

  1. @babel/runtime
  2. broadcast-channel: for sharing data between multiple browser tabs or Node processes
  3. match-sorter: sorts words

SWR:

none

Security concerns:

Testing & rollout:

  1. Since, both React Query and SWR use hooks, they can be tested using React Hooks Testing Library
sakshambhatt commented 2 years ago

@ankushdharkar @shreya-mishra, did you have a chance to look at the RFC? If you find it to be exhaustive pertaining to the issue, then might we go ahead and have a discussion with some other members and start executing?

shreya-mishra commented 2 years ago

@sakshambhatt let's discuss it at @10pm today if you are available.

sakshambhatt commented 2 years ago

@ankushdharkar , what will be the next steps for this issue? Creation of data model, data flow is separate issue than state management, right? Will we be asking people for their comments on the above doc?

yesyash commented 1 year ago

Approach 3:

make our own external store and link it using useSyncExternalStore ? Instead of using a library like zustand/Redux.

yesyash commented 1 year ago

Approach 4

Use Jotai as the state management library to handle UI state. It can be a good solution when we start integrating different functionalities (modules) like goals, members site, status site as it allows us to create atoms that can be specific to each module & if we want to keep our state within our component tree.

Sharing a link from Jotai's official site comparing Jotai and Zustand as they can be very similar when compared from the outside. https://jotai.org/docs/basics/comparison

shreya-mishra commented 1 year ago

Approach 5

Let's start with the Redux saga or Justand and implement the other management library and just compare which one is better, as RDS is all about learning, implementing, breaking, and rebuilding things.

sakshambhatt commented 1 year ago

How would we measure and compare the performances of these different approaches?

yesyash commented 1 year ago

How would we measure and compare the performances of these different approaches?

how about testing the following metrics?

  1. Bundle Size.
  2. Memory usage.
sakshambhatt commented 1 year ago

Ankush has suggested to search for all the references related to state management in React Native app on the internet. Post that, we would ideally pick the strategy that is standard across the industry. If we are not able to find good resources, that is an opportunity to write blogs on it.

sakshambhatt commented 1 year ago

@ankushdharkar , found one good blog https://tech.groww.in/simplifying-state-management-with-zustand-redux-saga-vs-zustand-12006a9f55de

sakshambhatt commented 1 year ago

Redux team has been advising against Sagas generally... https://twitter.com/acemarke/status/1618630292520177668