How does Redux actually communicate with the DB?

I’m sorry if I may sound (a lot) confused, but I actually am about this.
So let’s say I have created my Async Thunk. I build my reducers to handle POST requests. Then what? The state gets updated and the change reflects on every component subscribed to it through the selectors; this I got. What about the other side of the communication? How does state change get reflected into the database? Does the state actually get updated INSIDE the database and THEN back to the store? Or is there something else going on behind the scenes?

Say for example I setup an Express app on port 5000; then I set it up with my favorite ORM (or ODM, doesn’t really matter in this circumstance) to handle GET, POST, PATCH and DELETE requests. Then I expose an API point for each of these routes. Then let’s say on port 8000 I have my React app powered by Redux. What happens when I hit one of those endpoint that ACTUALLY changes the database?

I’m not sure I understand. We agree that the redux state and the DB are completely different things?

How does state change get reflected into the database?

Your client app calls your server and the server tells the DB server to make the changes requested.

Does the state actually get updated INSIDE the database and THEN back to the store?

That depends on you. Is the data you want updated in the client just the same data (or is derived from) that you are sending to the server? You can have optimistic updating of the data - you assume that your call will succeed and just use the copy of the data you have to update your client’s redux state. Sometimes that makes sense. Sometimes you want to make sure the DB update worked or need some info from the response from that so you wait until that gets sent back.

Both of those work, depending on your needs. But in both cases, you are updating the client’s redux state. There may be libraries that allow the redux state to be automatically updated, but not in vanilla redux and I don’t remember that being a thing in thunk.

Thank you for your answer!

Yes, of course. Which is pretty much the source of my confusion :joy:

Yes, this is clear as a general mechanism. My doubt arises when one throws a state manager in the midst. Since (at least, from what I understood of it) it acts as a “bridge”, or some sort of staging area of the data, my (probably wrong) understanding is that if one performs a POST request on the client side, he/she does so through a reducer, which updates the Redux state. This is where I get confused the most: what happens when because of this state change in the Redux store, there is a mismatch between the data in the store and the data in the database? Does the Redux action update the DB (by hitting the endpoint), which then in turn causes the DB to send back updated data to the store as a state, or what the client sees after the update is actually the Redux store, with a promise that it will also get updated into the database?

Since (at least, from what I understood of it) it acts as a “bridge”, or some sort of staging area of the data, my (probably wrong) understanding is that if one performs a POST request on the client side, he/she does so through a reducer, which updates the Redux state.

No, I’d say that redux manages your state locally, period. That is its job. If we take thunk out of the equation, you would have to have some helper function (or whatever) that is going to have to do two things - perform the POST, etc. and dispatch and action to update the redux state (if needed). These are two separate actions. It can get complicated - when do you update data? What if it fails and needs to update a different part of state? What if other actions need to be dispatched?

That can get messy so things like thunk and saga were invented. With those, you can move that logic out of your component and just call a specific action that triggers your thunk or saga. A thunk does it with a callback function (if I remember correctly) and sagas use generator functions. But they both do similar things - they allow you to elegantly handle async situations and allow you to extract all of that logic to somewhere else. But in both cases, you are still going to have to tell it how to update redux state and how.

This is where I get confused the most: what happens when because of this state change in the Redux store, there is a mismatch between the data in the store and the data in the database?

If you don’t want that, then don’t do that. There are different flows.

  1. Make POST.
  2. Assume it will succeed and update local state with the same data.
  3. Deal with any errors as they come.

or

  1. Make POST.
  2. Wait for response from POST.
  3. Update local state with correct data if successful, or deal with the error.

Does the Redux action update the DB (by hitting the endpoint), which then in turn causes the DB to send back updated data to the store as a state…

No, unless you are dealing with a library that integrates these things (it sounds like you aren’t) then you are in charge of those. They are two separate actions and you choose how to deal with those.

Does the Redux action update the DB (by hitting the endpoint) …

Traditionally, redux should have nothing to do with your DB. The only job of redux is to manage your local state. Things like thunk and saga allow you to have other effects in your app, including making http requests and saving data from the response into your local state - but you still have to do that yourself.

…which then in turn causes the DB to send back updated data to the store as a state,

That can work, but it isn’t redux that would normally to that, but a thunk or saga. They can handle the async action and tell redux to handle the state update, either before of after the http request, depending on your needs.

…or what the client sees after the update is actually the Redux store

The client should only be seeing the redux store, not what is directly in the DB. They are two different things, the DB and the redux store. Your client doesn’t look at the DB itself. You make queries to the DB (through your server) and those get reflected in the client’s redux store.

…with a promise that it will also get updated into the database?

That is where error handling comes in. See the two ordered lists above. It just depends on how you want to handle it.

Maybe it’s analogous to balancing checkbooks. It used to be that you would write a check. You would update your ledger (local state) with your updated balance, assuming that the check will go through normally at some point. So, your ledger is optimistic, it is showing what expect everything to be when the check eventually gets processed. Most of the time that is going to be fine and if you keep meticulous records, your local ledger and the bank account will match, barring the processing of async operations like receiving and processing the check - but everything matches up in the end.

Of course, there is the possibility that the check will bounce. When you find that out, you adjust the local state accordingly.

That is the optimistic approach. Some accounting systems don’t update until the check clears. That would be the pessimistic approach. That would be analogous to not updating local state until after the request completes and lets you know what data was saved.

Sorry, I just realized I expressed myself poorly.

Actually yes, I am. When I talked about Redux I was actually referring to the whole React-Redux ecosystem, hence including the interactions with the server and, specifically the thunk (I don’t know how to use sagas)

So Redux updates the local state, and it’s completely decoupled from what the middlewares do with the API layer, is that correct?

Okay, but by “local state” you mean the one of the components? If that’s the case, what’s the point of even using a state manager, if React already provides a way to manage the state of the components? Okay it’s an abstraction which may be useful in some cases, but from what I understood Redux is mostly supposed to contain states that components subscribed to them are supposed to render; my doubts are exactly about the interaction between Redux and “where to get the state”.

So Redux updates the local state, and it’s completely decoupled from what the middlewares do with the API layer, is that correct?

All redux does it handle local state. That’s what it was designed to do. Thunk is middleware that intercepts the dispatch process and uses a callback to handle async actions.

Right, but what I was referring to with that comment was a library that handles both your local state update AND your DB update at the same time, automatically. To the best of my knowledge, neither thunk nor saga do that. Thunk does not update your DB for you, unless you tell it to. All thunk does is allows you to more elegantly handle asynchronous actions.

Okay, but by “local state” you mean the one of the components?

It is confusing. In this context, when I say “local state” I mean the redux store, not the component state. (I really wish redux had called it “store” and not “state”.)

And just to be clear, even if you are using redux, you might still use component state for things, like handling a controlled input or whatever - things that the entire app doesn’t need to know or need to be persisted.

Okay, let’s start fresh for a second.
Say I have a form developed in Vanilla React (without React-Redux Form or other such third party libraries).
Say there are local states like the input and the onChange handlers, maybe something like:

const [checked, setChecked] = useState(false);

which of course I would never think of storing in a Redux store, since it’s a state that pertains strictly to the component at hand.

Then, say I also want to render something from the database (for example in a todo list, I want to render the todo list right below the form). For that, I would do something like:

const { title, description, isDone } = useSelector(state => state)

which means that this data is in the Redux store, and it is fetched and rendered by doing

useEffect(() => {
   dispatch(getTodos())
   }, []);

where getTodos is an action creator like

const getTodos = () => async(dispatch) => {
    const res = await fetch(URL).then(res => res.json()).catch(err => console.log(err))
    return res
}

Then, I want to submit my local state on the component (which is handled by the various useStates). Should I dispatch an action to pass local state to Redux, and THEN from Redux performing the POST to the endpoint which handles the DB inserting, or should I perform it DIRECTLY into the DB, and then modify getTodos() to periodically rerun and watch for changes into the DB, which in turns would cause the Redux store to update and hence the React component to rerender?

Yes, I agree 100% with that.

Should I dispatch an action to pass local state to Redux, and THEN from Redux performing the POST to the endpoint which handles the DB inserting, …

I’m not sure what you mean by passing “local state to Redux”. When I used the term “local state” I was returning to the redux state. I use component state to refer distinguish. Perhaps we don’t use the term “local state” but call it “redux state” to avoid confusion.

You should never need to pass redux state to redux - it already has it. You may pass a local state to an action creator if it needs it.

…or should I perform it DIRECTLY into the DB,…

What do you mean by “directly”? The client doesn’t have access to the DB. Usually you are making an API request to an http server that is making a request to your DB server. I don’t know how you would have direct access.

and then modify getTodos() to periodically rerun and watch for changes into the DB, which in turns would cause the Redux store to update and hence the React component to rerender?

OK, let’s make a distinction. In one way of thinking about this (the way I was thinking) is that you dispatch your action, it calls your thunk, your thunk makes your async call, at some point the value gets returned, you update your redux state, and the since your component is subscribed to that state (through the useSelector hook) so your component automatically updates with the correct data.

But when you say, “watch for changes into the DB”, that is something entirely different. So, you are saying that someone else might make a change to your DB and your app will automatically know and update? That is a very different problem.

Most apps don’t do this. I don’t know if there is some hook you can use to listen for changes in the DB, but off the top of my head, but one option would be to set up a socket between your client and server so the server can inform the app if the DB has been modified. I’m sure someone has come up with an elegant library that handles this, probably even one that works with redux - I just haven’t dealt with this yet. Another option would be to just requery the server when you need to make sure the data is fresh. My banking app does this. It gets the account balance, etc. when I first go to it, but refreshes the data before I do some important operation - I can see because the loading screen comes back. It may also do it after a certain amount of time has gone by, making the data “stale”.

An example of something where you need to know instantly of all changes would be a chat app. Your client needs to know the second a new message is there and even when someone is typing. I imagine that this is usually done with a socket.

@groosterm the way you are talking about state and DB updates makes me think a lot about graphQL mutation.

There is a pattern called optimistic mutation where you essentially update the UI before you got the response back from the backend that everything went according to plan. This makes the UI feels instant as it’s not really waiting for any response.

Mind that this is supported by a complex mechanism of cache.

Also this means that your API needs to work with graphQL.
(all the above examples are taken from Apollo, a React graphQL library).

Reproducing the same with ajax would be incredibly difficult.
To me the best idea is to start simple:

Front end does something with data → FE send data to BE → BE does something with new data → BE respond to FE → FE does something with response.

Then if this paradigm fails you, you can think of other solutions.
Hope this helps. :sparkles:

2 Likes

What I mean is: I hit an endpoint, which I know it to be configured on the server to interact to the database, so let’s treat it as a black box; it’s there, I know it works, it puts stuff in the database if data is sent to it as a JSON body. What I’m asking is: this JSON should live inside the Redux store (configured with thunks and so on to dispatch async stuff), or the endpoints should be hit directly from within the component. To put it differently: I dispatch an action to update the state AND perform an axios post request through the onClick method, or I dispatch the action on the onClick method, which updates the state AND THEN the update on the state gets asynchronously sent to the endpoint?

I have heard about GraphQL, I never understood exactly how it differs from a Rest API. I’m a noobie :see_no_evil:

What I mean is: I hit an endpoint, which I know it to be configured on the server to interact to the database, so let’s treat it as a black box; it’s there, I know it works, it puts stuff in the database if data is sent to it as a JSON body.

Sure, that makes sense.

What I’m asking is: this JSON should live inside the Redux store (configured with thunks and so on to dispatch async stuff),

Should that data live in the Redux store? That is up to you. With the configuration you have (Redux/Thunk), whether or not you store it in Redux is up to you.

or the endpoints should be hit directly from within the component.

That is up to you, but that kind of defeats the purpose of using a Thunk. If you didn’t have Thunk hooked up, sure, that would be a way to do it, you have a function in the component that hits your endpoint and then dispatches the action to update Redux store. They are two separate actions.

With a thunk they are still two separate actions, but they are hidden in a thunk. You dispatch your thunk and inside that thunk’s callback function, you do two things: do your http request and dispatch an action to update your redux state - in whatever order or manner you want.

Marmiz mentioned GQL, which I like a lot and there are libraries for it that will handle some of these things for you. I might suggest though that that is a different world and I might suggest that you get comfortable with what is happening here, in a more standard flow, first.

To put it differently: I dispatch an action to update the state AND perform an axios post request through the onClick method, or I dispatch the action on the onClick method, which updates the state AND THEN the update on the state gets asynchronously sent to the endpoint?

Which do you want? I keep saying this. Do you want to optimistically update the redux state, that is, assume the POST worked and fix it later if it doesn’t? Or do you want it to wait for the POST to succeed and then update the Redux state. Both are reasonable options - you decide.

1 Like

Okay thanks, this solves my doubt! :slightly_smiling_face:

This topic was automatically closed 182 days after the last reply. New replies are no longer allowed.