I'm rather new to ReactJS and I'm trying to figure out when it's to my [webapp's] advantage to implement Redux store instead of just using props. Is it better to use useContext?
The general use case is an event list viewer that needs to maintain a connection session to a database api and display its connection status. Also need to effect a "mode" change (i.e., "real world" vs "test" vs "exercise") across the application.
I've seen this Stack Overflow question, and this one too, but neither of them give any indication on what the threshold is for when store is better than props or context.
Its because the threshold can't be defined easily ahead of time. I would say its when:
The performance of your app starts crumbling because you have so much state.
The state management logic of your app becomes unmaintainable and horrible to the point where you are sufficiently annoyed to change it.
You happen to know ahead of time you have really complex state.
Optimizing too early is a hugely common pitfall. If your state is simple, and not huge, you'd have the exact opposite effect by using redux from the off -- unnecessary complexity.
My recommendation, without further context about what your app is and your use case (provide if so), would be start with context and deal with your problems when they emerge, unless you are really sure right now that your app is going to be huge and complicated.
Just to add one datapoint, I work on a pretty big enterprise application that basically consists of 50+ forms (which dont interrlate that much) and we've got by with context and local purpose-specific form stores just fine (and a network caching layer like URQL) with no real desire to change.
As another data point, I had a friend building some crypto dashboard that had many widgets all updating independently every few seconds. It was a complete nightmare. He moved everything to redux so he could buffer the state updates into one update across the whole screen every 5 seconds, and the issues went away. This is the kind of unique and complex case where you need to consider it. So...it depends.
Another type of app where I've found it necessary is anything that is hugely collaborative. Like an online real-time multiplayer game or live doc editing. The complexity goes through the roof with this sort of thing.
A running thread with those examples is the state is both complex and truly global in nature.
The experience to "know" can't be put into words or quantified. It comes with experience. But going with simple context, and changing it only if you have a gut instinct something is badly wrong architecturally, is a fair starting point imo.
I'll also add, redux has become synonymous with "all state at the top". Which depending on your app, may not be a good idea. State scoped to different subtrees is often what you want. If its the complexity of the updates and so much the scale of the size of the data, that can also be reduced with solutions like https://xstate.js.org/
Related
I would like to understand more about the best practices for passing props around parents-child in react. the problem comes from having a standard way of doing this in a medium-large project to minimize confusion and technical debts such as performance optimization. So far, I only knew these methods on doing this:
standard prop drilling
Pros: easy
Cons: will become unmanageable in complex feature
utilizing React.Context
Pros: medium difficulty, naturally separate from main component
Cons: more time to write, may be unnecessary for smaller components, will do re renders that will cause performance issues headaches in, for example, large forms.
using global state from 'reactn' module
Pros: easy
Cons: will get unmanageable for large projects that have tons of components, cannot prevent rerender AFAIK.
using Redux
Pros: robust and compatible with firebase (react-redux-firebase, redux-firestore), can prevent rerender using areStatesEqual,
Cons: more boilerplates, more work to do for simpler state management
is there a guideline on standard practices on doing this? what do you people use for medium-larger projects? thanks!
The following answer is subjective!
There are basically 3 categories that I am aware of.
Keep everything local ( For any size of app which doesn't deal with sibling dependencies this will work fine. May cause some prop drilling, though it should be avoided as possible, it's not an anti-pattern. You come with better approaches to handle this i.e. PureComponent, React.memo, shouldComponentUpdate)
Keep everything global(redux/reactN/...) (have not seen this approach in my experience, not recommended in my opinion as requires you to hit central state every time when there is a change)
Keep a mix of both. (Highly seen this in medium to large scale projects, we use this approach with redux)
Choosing an option:
Personally speaking, irrespective of the size of an application one can start with the first approach and add the central state later when required(if you are not sure where to put states).
If you need to manage some state centrally from the beginning it can be added from start(if states are clearly defined).
If you choose any one of the above two approaches, to begin with, at one point in time you would need to decide either go for first-party i.e. React Context or a third party i.e. Redux, ....
You have already stated the pros and cons of these, you can compare and see which one outweighs the others.
For a simple answer from the list you provided I would suggest redux, writing actions and reducers does add a certain amount of overhead, and as react evolved and matured it now seems you can manage large applications w/o the use of redux: https://medium.com/#dan_abramov/you-might-not-need-redux-be46360cf367. But once you get how redux works you will be able to scale with ease. This is a good solution for react-redux beginner-intermediate level devs.
The best suggestion I have for you is to use react only.
useContext and useReducer will get you very far, but it requires an intermediate - experienced development skills. This approach will force you to invest time in data-structure, encapsulation of components and use of advance react patterns. (I would enroll to something like https://kentcdodds.com/workshops/advanced-react-patterns)
Is this a good solution?
https://github.com/immutable-js/immutable-js/wiki/Immutable-as-React-state
I need to put nested objects in my state. This solution seems simple enough in code, but I'm wondering if there are any reasons not to take this approach.
TL/DR: I recommend immutable for anything bigger than a simple news-list, together with redux-saga. But I would and don't use it for component's local state.
We have a big React app (JS, not TypeScript) that has all the state as Immutable objects.
The recommendation usually is the same as with redux and redux-saga: If you don't know why you need it, you probably don't. But here is the thing, if you start without it and later notice that it would be helpful, you are already deep in a mess and it's hard to switch over.
Immutable doesn't add obvious business value, but it reduces the chances of bugs and prevents you from doing things that might look good now but in the long run increase the cost of development. Especially when your dev team isn't an experienced bunch of seniors or generally tends to not strictly follow rules.
However, in my opinion, it is unecessary overkill for an components internal state, at least if business state is stored in your global redux state.
PS: Immutable is mature and probably doesn't need patches much, but it has to be said: Development of immutable essentially is stopped, they are discussing to bring in new people but who knows how that turns out. There are similar libraries which are more active
I have an offline React web app where all data is stored locally in indexedDB. There is no server other than the file hosting for static assets. I am getting to the point where I am starting to look into using redux now but I am trying to understand the tradeoffs between moving more data into the store and continuing to rely on the DB. What's the idiomatic way of using a local db with redux?
Currently my app is composed of several container components that each fetch data from the db in componentWillMount. One option for integrating redux is to keep this mostly the same, with the only difference being the state is kept in the store and data is fetched using actions and thunks.
Alternately, I have seen lots of example code that loads all the data into the store at launch. This makes the whole app more deterministic, easier to test and reproduce. Switching between the main components would happen instantly (at the expense of initial app load). But I lose the benefits the DB provides like indexes and nice queries.
It seems like it would be unreasonable load literally the whole db into the store, at least in my case, that would be about 10MB of data, maybe more. So I will always have at least some components which will need to continue fetching their data on mount. But there's a subset of data which is central to the app and can be argued that table should be loaded in its entirety (this would be about 5,000 to 10,000 objects, probably).
What's the idiomatic way to work with local storage and redux? I get the sense that async fetches in componentWillMount is not idiomatic if it can be avoided. Even in instances where the state is small enough that it can be fully loaded into the store, is it worth giving up the benefits of a nice efficient query interface?
Edit: I should mention: I am using Dexie, which is a really, really wonderful library for working with indexedDB. It's fast, has a nice query interface, handles migrations etc... I'd really like to continue using Dexie unless there's a really strong reason to do otherwise.
For reference, here's a discussion on this topic on Dexie's github. The general take away form that is "it depends". Not quite the answer I was looking for, so I am hoping to get more insight if possible.
Answering this myself with what I've discovered so far. If I better answer comes along I'll be happy to mark it accepted.
TL;DR: It really does depend. The idiomatic way to do things is indeed to put as much in the state as long as makes sense. However, it is not un-idiomatic to asynchronously fetch data from elsewhere when it makes sense. Many applications would simply be impractical otherwise.
Dan Abramov's egghead tutorial (even titled "Building React Applications with Idiomatic Redux") goes with the approach of having all state in the store and persisting it a s one giant blob (or the relevant slice) periodically.
This has the advantage that you use the redux store as usual and persistence is essentially transparent. If your data is small enough where this isn't a problem this is great.
As #seanyesmunt noted, there is redux-persist, which basically does a more sophisticated version of this.
Of course, shortly after that he then rewrites the tutorial to fetch data from an API. At this point you can just pretend that API is IndexedDB instead, it's really no different. You lose some benefits of redux by not having completely deterministic state as a whole, but in many cases you have no choice.
I ended up doing essentially the same thing as Dexie's Redux sample code. Basically, using thunks to async write to the DB on certain actions.
EDIT 2020-12-18: I recommend using dexie-react-hooks and the useLiveQuery() hook. It's an amazing experience to work with takes away all complexity around this. See also this blog post about it.
My old answer was:
This question is of large interest to me as well as I have been elaborating with react and dexie for the last project I've been in. I am personally examining how graphql could address this scenario, but I am still learning. I hope to provide an example of a graphql/dexie. Of what I understand, graphql would act as the service layer and its "schema" (backend store) would use the dexie queries required to produce the more flat an simplistic graphql data requirements. I will be looking at some ready-to-use grapql sample from Apollo or Facebook to get started and I believe it will be simple to use.
I generally don't think it scales to read entire db into memory. And I believe application startup is crucial to end users so I really hope to find a perfect architecture for this. And currently my hope goes to Graphql.
I'm developing Web project with react.
But bigger code size the speed is slower. And All code in one system is easy to be complicated and hard to maintain
Is there a way develop by each component with redux, side effect all in one module?
For example, modulizing one component(comtainer) with is's action, stores, side effect. And attach main code with build system..
At the end of the day, a single store will contain all state in redux. The exception to this, is if you choose to run two seperate apps on the same page - but they wouldn't be linked in any way whatsoever (so ignore it).
However, you can use combine reducers to join reducers from multiple components into one store while keeping them separate. For the majority of apps this will suffice completely, and I would find it hard to imagine it would cause performance issues unless it is set up incorrectly.
Your question doesn't lend itself to one concrete answer, but rather patterns. I would look into "ducks" for redux - its not a technology or library, but rather a pattern for keeping your stores and components modular.
Ducks: https://github.com/erikras/ducks-modular-redux
Explanation: https://medium.com/#scbarrus/the-ducks-file-structure-for-redux-d63c41b7035c#.36dsdqd5q
Personal favourite structure doc: https://hashnode.com/post/tips-for-a-better-redux-architecture-lessons-for-enterprise-scale-civrlqhuy0keqc6539boivk2f
If you still feel like redux doesn't align to your modular app, you can consider not using it - sometimes there is no need for it. https://medium.com/#dan_abramov/you-might-not-need-redux-be46360cf367#.p7j6cioou
I've read a lot of heated and contradictory information about this sort of subject and I have no dog in the fight - I have the advantage of an open mind.
Let me walk you through my very informal thought process that led me to think, after using a boilerplate with everything in the relay kitchen sink, that I still needed something like redux.
In more than a few scenarios, sufficient redux boilerplate takes less time and much less thought than the sufficient GraphQL and relay boilerplate
The abstraction of actions in redux is a good thing that keeps many programmers out of trouble by forcing them to separate concerns and to encapsulate the internals of a request / how it works vs the existence of one.
Specifically, if I am making a canvas editor with lots of tools and brushes, it seems like it would take a long time to get started the right way in relay making all those mutators and queries and so on with care for persistence.
But if I say, you know, I don't need my app to know every state ever of everything, without something like redux, there is no alternative to either managing state via some sort of big container object or winging it, both of which are inferior to redux
Therefore my instinct that redux has its place in this scenario is the right instinct
However, I might just not understand how GraphQL and relay are supposed to be used.
Therefore, I am asking for concrete answers about 1) whether this is a fairly objective or subjective question, 2) whether there is a consensus or not, and 3) if I should care.
One more thing - if it is the case that redux is fair game in such a scenario, is it still a good rule of thumb that my app ought to have a single store? Or can I start using redux more modularly and in mroe of an adhoc fashion?
By the way here is a more simple scenario: I want to use a Stepper from material-ui which requires State. Without redux my choices are either to faithfully do that at the relay level or below, wing it in the components, or try to fudge it somehow or mix it. The only sound option is the first, and that takes time.