Post request redux thunk - redux

I have GET requests and normally when those succeeded I save data in store, but for POST requests I need to know if it succeeded or not, in order to execute some code (show a message and redirect), the docu says you can use an isLoading variable, but it just says if the service is working but not if it succeeded, if I try to create a new success variable in the store, it will be turned on forever after the request and I don't need that either. I tried returning a promise from the action creator and handle response directly inside the component but it looks like the same to call axios there instead of using redux.
My action creator looks like this:
export function createProject(userId, projectName) {
return function (dispatch) {
dispatch({ type: projectsActions.START_CREATE_PROJECT });
return ProjectsService.createProject(userId, projectName).then(() => {
dispatch({ type: projectsActions.SUCCESS_CREATE_PROJECT });
}).catch((error) => {
dispatch({ type: projectsActions.ERROR_CREATE_PROJECT });
throw error;
});
}
}

I understand where your doubts are coming from, it doesn't seem appropriate to have a field on your Redux store only to know the success of a one-time request.
If you only need to make a post request and only care about it's result once, the simplest way to do it is to use state in the component making the request. Component-level state is easily manageable and gets removed from memory when the component is unmounted, but on the other hand you may want to have a single source of truth for your app. You have to make a choice, but your Redux implementation is correct.

Related

redux-saga and firebase - Can't log the user out in a clean way

As a preface, let me mention that I have never used redux-saga or Firebase before today. I'm currently playing around to get a feel for both technologies.
I'm probably just missing a small concept, but I can't seem to get signout to work on my app. I figured that I should probably use call() to manage side effects within a saga, but nothing does the trick.
Here's the saga in question:
export function* deauthenticateUser() {
yield takeLatest(DEAUTHENTICATE_REQUEST, function* () {
try {
yield call(firebase.auth().signOut)
yield put({ type: DEAUTHENTICATE })
}
catch (error) {
yield put({
type: DEAUTHENTICATE_FAILURE,
payload: error,
error: true,
})
}
})
}
I confirmed that calling firebase.auth().signout() directly works, it's only when using call() that I get the error action. Note that there's also no payload when the error gets dispatched.
I checked in Firebase's documentation, and apparently firebase.auth().signout() returns a promise with nothing as it's content. I'm starting to wonder if that wouldn't be the problem, maybe redux-saga does not like having no result in it's promise when using call()?
How would one handle authentication and especially logging out with Firebase and redux-saga?
From a comment from NULL SWEΔT, I had to call yield call([firebase.auth(), firebase.auth().signOut]).
The reason for this is because of JS' context and how this works. More details by reading this and this (read documentation for call([context, fn], ...args)).

Redux redirect using redux-thunk

Hey guys I have a function as so:
function dispatchSignup(username, password) {
return function(dispatch) {
const newUser = {username: username, password: password}
axios.post('/signup', newUser).then(() => {
return dispatch(signupAction)
}).then(() => {
return dispatch(push('/'))
}).catch((error) => {console.log(error)})
}
}
This function is first sending a request to my server to signup. If successful, '.then' runs and dispatches a signupAction. I then call another '.then' after this, which should only run after this signupAction has been dispatched, which will redirect the user to '/' aka. my home page. The problem I'm having, is that yes they signup, and the url pushed works, however it's not actually rendering the component at '/'. What is happening here? It's as if they're blocking one another, although I'm not really sure. Redux-thunk is async I thought, so the second action I call won't be dispatched until the first has successfully dispatched.
Any help would be greatly appreciated, thanks.
I then call another '.then' after this, which should only run after this signupAction has been dispatched
This assumption is incorrect. The dispatch function returns the action being dispatched, not a Promise. Assuming signupAction is also using redux-thunk (returning an action), then that would explain why your call to push('/') is happening immediately and not waiting for your signup process to be complete.

How to access custom response values from a page script?

This might sound like a silly question but I have really tried everything I could to figure it out. I am creating a variable and adding it to my response object in custom Express server file like so:
server.get('*', (req, res) => {
res.locals.user = req.user || null;
handle(req, res);
});
Now I want to access this res.locals.user object from all of my pages, i.e. index.js, about.js, etc., in order to keep a tab on the active session's user credentials. It's got to be possible some way, right?
P.S.: Reading some thread on the NextJS Github page, I tried accessing it from my props object as this.props.user but it keeps returning null even when a server-side console.log shows non-null values.
The res object is available on the server as a parameter to getInitialProps. So, with the server code you have above, you can do
static async getInitialProps({res}) {
return { user: res.locals.user }
}
to make it available as this.props.user.

Login app with Redux & ReactRouter

I would be thankful if someone could point me into a right direction in understanding the Redux architecture.
I should implement "reducer" functions that will handle my actions.
Reducer functions should be combined and create a store.
Lets say I have a LoginForm (React) component, that makes a XHR request to backend API, and receives a JWT token in response.
When I get the response from the API I should dispatch an action like:
store.dispatch({type: "USER_LOGGED_IN",
payload: {username: "john", JWT: "..."});
This updates the state of my application.
What next?
How do I route to to next page? How do I rerender my components (like navbar, etc.) with the logged in username?
Do I use listeners for that?
Let's say you've a method to authorize user:
import { browserHistory } from 'react-router';
// ...
function promisedApiCall(inputData) {
// ...
// api request to backend with input data
// return a promise
}
/*
* on form submit we call this with input data
*/
function authorizeUser(inputData) {
return promisedApiCall(inputData)
.then((response) => store.dispatch({
type: "USER_LOGGED_IN",
payload: {
username: response.userName,
JWT: response.JWT
}
}))
.then(() => browserHistory.push('/success/path/url'))
.catch(() => browserHistory.push('/failure/path/url'));
}
Assuming you have the following prerequisites:
Created redux store and store object is available in the scope where authorizeUser() is executed.
The method promisedApiCall is the function which makes the request to backend with input data from LoginForm.
promisedApiCall should return a promise. [this is really important]
Configured react-router with redux
Once this is complete, app state is updated with user info and also user will be redirected to a new page. This post explains more about programmatically redirecting using react-router.
Access you app state in you component using Redux connect.
Now you have the user info in your component as props.
react-router has a component browserHistory.You can import that like this,
import {browserHistory} from 'react-router';
And to change your route,
browserHistory.push(<route_where_you want_to_go>);
This will let you change the route.

Intercepting HTTP Requests in Redux

Many redux examples show making HTTP requests directly in an async action; however this will result in an exterme amount of duplicate code common to all requests, for example:
Retrying failed requests based on status code
Appending common HTTP Headers to each request.
Invoking additional http requests based on response (ie: oauth token refresh)
Aborting in-flight requests on route transitions.
My gut feeling is that a middleware could be used to make http requests (in the same vein as redux-api-middleware) which can keep the in-flight requests in the store - however I am also wondering if I'm leaning on bad habbits - is a little duplication a small price to pay for immutability?
Your action creators are just JavaScript functions.
If you have duplication between several functions, you extract the common code into another function. This is no different. Instead of duplicating the code, extract the common code into a function and call it from your action creator.
Finally, this pattern can be abstracted away with a custom middleware. Check out the “real world” example in Redux repo to see how it can be done.
All but the aborting could be accomplished while staying immutable by using a request factory which attaches .then and .catch (or equivalent, depending on promise flavor) to the request before returning it.
you can have a action which executes its operation in addition it calls another action, to achieve this you need to have a redux-async-transitions, the example code is given below
function action1() {
return {
type: types.SOMEFUNCTION,
payload: {
data: somedata
},
meta: {
transition: () => ({
func: () => {
return action2;
},
path : '/somePath',
query: {
someKey: 'someQuery'
},
state: {
stateObject: stateData
}
})
}
}
}
and here is for asynchronous call
function asynccall() {
return {
types: [types.PENDINGFUNCTION, types.SUCCESSFUNCTION, types.FAILUREFUNCTION],
payload: {
response: someapi.asyncall() // only return promise
}
meta: {
transition: (state, action) => ({
onPending: () => {
},
onSuccess: (successdata) => {
//gets response data can trigger result based on data
},
onFail: (promiseError) => {
//gets error information used to display messages
}
})
}
}
}
Calling http request in middleware is the same bad ideas as calling it in action creators. You should focus on making our reducers powerful enough to handle asynchronous effects as well as synchronous state transitions. The best way i found while working with redux is describe effects in the reducer(http request is the effect) and then handle it with library like redux-loop or redux-saga
For avoiding code duplication you can extract common code to request function and use it for handling http effects

Resources