Dispatching logout from outside of a React Component - reactjs

I have a doubt with react-redux
I'm making an app that involves authentication, and from my server, if the auth fails I send back an error.
I made a function specifically for protected fetching, what i'd like is, if there's an error on the response, dispatch an action to log the user out, however this function isn't inside a react component and i've been told exporting the store isn't a good practice, so what's the right way to do this?

Once you get the error you should probably report it somehow back to your component. You could have it as part of of your store... sometimes people use bool value, sometimes error text. In any way that error has to make back to your component. Your component will check for error (as you use redux, you will probably bind store's error value to a component's property. As an effect, inside of your component you will evaluate the value and call a redux action to log user out. The action will change store parameters, clean local storage, it can even call async server actions to log out on server side (see how redux-thunk and similar middleware works).

Related

Redux Tookit, How to dispatch action in a non component function?

I have a global toast, which I am opening using redux slice. I need to open the toast for error message when call from api fails in api-slice of rtk-query.
I have seen the answer, using store.dispatch method, but this causes dependency cycle. Is there a way to do this?
Yeah, you should always avoid directly importing the store into other application files.
Ideally, none of the rest of your code would ever need to refer to store directly.
Depending on where in the RTKQ setup you need to trigger this toast, you may have access to dispatch as part of the lifecycle function arguments.
In the worst case, you can use our fallback recommendation to inject the store into the necessary files from the app setup logic.

Best way to integrate React, Redux, Redux-Form, and React-Saga?

I have read everything I can find on how to use react-saga and redux-form together I'm stuck at a crossroads and need some advice.
Here is how I ended up here.
I chose to work with Redux because it makes sense for my app and I don't have any problems there.
Switch from Thunk to Sagas
I started working on my async api calls to populate my app with data. I'm using a lot of data grids and I'm not sure where I'll end up on latency as some of the queries are quite complex.
When I started working on the action creators and methods for doing background polling of data I realized that Sagas were going to be much easier than Thunk.
I made that switch and I'm happy with it. Handling any errors from the api calls is being handled by an action creator that updates redux state container for all of my api calls. Errors are displayed by populating a modal based on those state changes.
Introduciton of Redux-Form
Once I started working on posting form data back to the api things got interesting and I realized I was about to write a lot of code to handle it all through Redux. Redux-form simplified things as it has a state container for everything form related and makes it really easy to setup and validate forms on the client side.
Redux-form handles all of the form state in my configuration until the form is submitted.
I'm using a container component conected to a Redux store I created to hold state of api requests.
The form is a child component of the container that is connected to Redux through redux-form which handles all of it's state.
When the form is submitted I am calling a Redux action which in turn called a saga to post the data.
The result of the saga api call is to either dispatch a success or failure action in Redux. I am passing an object to the api state that contains the status (success/failure), an error object with any errors, and a return object where I can return things like the id's of records just created.
That works well when the error from the api is communication related. Because I'm updating the api state my higher level app components have access to it so I can do things like trigger a modal for errors not specifically related to the form data itself.
But when I started thinking of how I would handle any field errors that could occur if the client side validation was missing some logic I got lost.
In my current setup those errors would be on the api state object. I could put them into a modal but there would be no client side error handling on the form itself.
Redux-form can handle server side validation tied directly back to the form fields but only from a promise and from what I can tell trying to return a promise through action creators would be difficult if not impossible.
I can write a promise in my onSubmit function but I would have to call my saga function directly instead of triggering it through an action. Is that an acceptable pattern?
I guess I could trigger an action from the saga to populate my api state values but it seems backwards.
Basically I would prefer to handle comm errors one way (through my api state container) and form field data errors another way (back throu redux-form and it's error handlers) and I'm not sure which direction to take.
I looked at a module redux-form-saga which makes it possible to return a promise directly back to the form and therefore use the redux-form error handling after the api call but I'm not sure if I would be able to also trigger my api state actions at the same time.
Rather than continuing going down the rabbit hole and maybe over complicating things I thought I would solicit some advice from anyone who has had to deal with something similar.
I'm good with async background calls to populate my data grids but when I have to post data back to the api I want to make sure the user can't take any other actions until they get a response back.
This is the first section of many in this app so I want to create a design pattern that makes sense, is easily reproducible, is reliable, and easy to follow.
Any suggestions?
React-Boilerplate will help you integrate React, redux, redux-saga. On top of that integrating redux-form should be straightforward. React-Boilerplate uses all the current best practices of the community for a production ready app

Appropriate place to dispatch action for fetching server data

I'm new to React and I'm trying to figure out the best way to request information from the server based on the URL. I'm using Redux and React Router v4.
Let's say I have a route /foo/:id, and a component Foo that will render something based on id. However Foo needs some server data related to id to do so. I believe the way to accomplish this would be to use mapDispatchToProps to create a function that takes id as input, does some async work, dispatches an action, and ultimately updates the redux state.
My question is: where is the most appropriate place to invoke the dispatch? In this scenario, there's no form submission or button click to kick things off. Originally I was thinking of including a check for the id data in render() and fetching if it was not populated, but this felt wrong due to the side effects.
You can do it in componentDidMount of the Foo component, similar to this example from the Redux GitHub project.
Your intuition is right that render is not a good place to do so. Most people do it in the componentDidMount lifecycle method of the component.
On a relevant note, you will also want to do fetching also in the componentWillReceiveProps method like what they did here. Reason being if your user navigated from foo/1/ to foo/2/, the component is already on the screen and will not be mounted again, hence componentDidMount will not be called again. The fetching for the second user will be done in the componentWillReceiveProps method.
i think the best way to do the dispatch inside the componentWillReceiveProps() which would help you fetch some data before the component renders
It seems your use case is well-captured by the react-refetch package which you can find here. It provides a higher-order component that allows you to specify dependencies at specific API endpoints and then resolves them when a new instance of your component is created.
Importantly it injects the data into your components props using a synchronous abstraction of a promise called a PromiseState. This will allow you to conditionally render your component depending on whether the data is say pending, fulfilled, rejected, etc.
This is not attached in any way to Redux, it skips that layer entirely, so do keep it in mind that the response is directly injected into the component and does not go through your redux store's state.

Using Redux to display a notification in response to a network request

My web application uses React and Redux and UIKit.
It consists of screens A and B.
Screen A contains a button which - upon pressing - will send an asynchronous network request to post some data to a server.
If a user remains on screen A until a response returns from the server, they will receive confirmation about whether or not the request was successful.
The way I have implemented this using React and Redux is by having a component which is responsible for displaying a confirmation banner. This component listens to changes to a state called postStatus in my Redux store. When the user clicks on the button, 3 Redux actions with statuses PENDING, SUCCESS and ERROR are potentially dispatched. After they are dispatched - they are caught by the reducers which change the postStatus state accordingly. This state then gets mapped to my components properties and it is re-rendered to display a relevant banner.
However, if the user does not remain on screen A until a response returns from the server and navigates to screen B instead - I would like a notification to show up so the user is still aware of the status of the request.
My question is, what would be the most sensible way to implement this behaviour?
Here are a couple of things I can think of:
Create a react component that doesn't actually render anything - it just listens to postState and some extra piece of state that represents which screen the user is on. Implement the componentWillReceiveProps react lifecycle method and if the postState is SUCCESS or ERROR and the other state says that the user is on not on screen A - then call UIKit.notify() to show the notification.
Call UIKit.notify() when dispatching the SUCCESS or ERROR action if the user is not on screen A.
Call UIKit.notify() when reducing the state after being dispatched the SUCCESS or ERROR action if the user is not on screen A.
There are most likely a lot of other solutions so I'm keen to hear some.
I know I am late for the answer, but I stumbled upon this myself so here is what I did.
The way I look at it is that the temporary notification is an application side effect.
In my project I am using redux-saga, but you can achieve this using any other side effects library.
The code (using deleting an user as an example):
...
function* deleteUserSuccess(action) {
yield call(message.success, 'Successful deletion!');
}
const watchDeleteUserSuccess = function* () {
yield takeEvery(types.DELETE_USER_SUCCESS, deleteUserSuccess);
}
...
PROS: It is readable and it works.
CONS: The only downside that I see is that you make your sagas know about your UI library. But you can wrap it in a separate function/file/module to abstract the saga from it.

Setting defaul state in a reactivejs/redux app

In my current ReactJS component, I have to call a REST API and get the JSON. It is done in componentWillMount.
I have introduced Redux in my app. Where should I make the call now to get the JSON and set as the default state? Is it in Redux or my React app?
Any example appreciated.
You'll usually want to dispatch an action from componentDidMount (or Will depending on your lifecycle constraints). That action will kick off the XHR and usually return either a thunk (redux-thunk) or a promise (redux-promise-middleware). If a thunk, it will be set up to dispatch another action with the results, or with a promise it does that for you, then reduce that state in as per normal and bind it to the component.
A common practice is to have a configureStore.js file that exports a configureStore() function that handles the store setup (initial state, middleware, and enhancers) and returns your store. See the "real-world" example in the redux repo for an example of this.
In your case, a simple approach would be to request the data from your REST API when your app starts up, and then when you receive the response, call configureStore(initialState) (where initialState is the data you fetched) and then proceed with the rest of the app setup and initial rendering. This approach will add a little time to your app startup though, because its initialization will be paused while it's waiting for that API response.
Another option would be to just create your store normally (without the prerequisite API fetch), and then make the actual initial state request from your API after your store has been created. When that API response is received, you could dispatch an INITIAL_STATE action, and have reducers ready to handle that. In this approach, you'd probably want some sort of loading indicator in place during this initial fetch, since your app will have rendered or at least started to render during the API request.
If you're doing server rendering, you can just fetch the initial state data from the server side, and attach it to the window object of the index.html that you're rendering. See the "universal" example in the redux repo for an example of this. That'll allow you to simply grab your initial state from the window object when you create your store.

Resources