How to do something inside component after triggering a redux action? - reactjs

i want to domething inside component after an action is done.
for example i want to show a modal to user after a request is successfully done, or disable some elements if request is done successfully.
should i use callbacks? or promise? if yes, then how
export const fetchHorizontalSpecialProductsList=(virtinId)=> {
return (dispatch) => {
dispatch({
type: Types.REQUEST_FETCH,
});
HomeApi().specialProducts({vitrinId:virtinId,rows:8,page:0,frontTypeList:["SPECIAL"]}).then((response) => {
dispatch({
type: Types.REQUEST_SUCCESS,
payload: response,
});
//
.then(probably here)
//
}).catch((response) => {
dispatch({
type: Types.REQUEST_FETCH_FAIL,
payload: response,
});
});
};
};
when the request is successful i need to show a modal

You just need to connect to Redux store, for example, in Redux state you should declare these properties:
success: false/true.
Then with the action received is REQUEST_FETCH_FAIL or REQUEST_SUCCESS you just need to use the switch..case statement in reducer to change the variable to true/false.
Your container connected to Redux store, depending on the props success true/false, you can doSomething() you would like to do,

Related

Send Rest call in a loop

I have a Rest API that in order to get the end data AKA:ENDDATA I need to send few requests (depends how deep). So when sending the first request the return response will have in the body the nextUri and so on…
Basically I need to execute a list of Rest calls based on the nextUri till I reach to the end ENDDATA.
Is there a preferred way to do this with React & Redux\redux-thunk.
export const find = () => dispatch => {
dispatch({ type: FIND_CUSTOMER_START });
axios({
method: 'post',
url: '/v1/...',
headers: { 'X': 'XXX1' },
auth: {
username: 'XXX1',
password: 'XXX'
},
data: 'SELECT * FROM .....'
}).then(function (response) {
// Need to find the nextUri ... before update teh state
dispatch({
type: SUCCESS,
payload: response.data
});
}).catch(function (error) {
dispatch({ type: ERROR, payload: error });
});
}
Thank you
Define your api call in a redux action
Inside a component lifecycle method you can call this action. As well as map the state from the store to your component.
When the action updates the state it will cause a re-render and call the lifecycle method. In the lifecycle method you can check to see if ENDDATA is true and if not call the action again.
Inside render you can have the same conditional as in the lifecycle method and have it return a spinner to indicate loading.

How to set state the data in componentDidMount method from the epic redux-observable

I am new to redux-observable. I have an epic function which request an api call and emmit a new success action. What is the clean way to get the data in my react view? In my componentDidmount method I call the getUsers redux action. I wanted to set the state in componentDidmount but It will run only once and will not wait the promise epic.
const getUsersEpic = action$ =>
action$.ofType(GET_USERS)
.mergeMap( action =>
Observable.fromPromise(
axios({
method: 'get',
url: API_USERS,
headers : getHeaders().toObject()
})
)
)
.flatMap((response) => {
if(response.status == 200) {
return [{
type: GET_USERS_SUCCESS,
data: response.data,
status: response.status
}]
}
else {
return [{
type: GET_USERS_ERROR,
message: 'error',
status: response.status
}]
}
})
.catch( error => {
// console.log('error', error)
return setResponseError(error, GET_USERS_ERROR);
});
You dispatch an action in componentDidMount() that is intercepted by redux-observable and used to make ajax call. As a result, you get GET_USERS_SUCCESS or GET_USERS_ERROR action dispatched to redux at some point in the future. Generally, there is no way to await these actions in components. And I think it's a good limitation because this restricts async handling in the component which can in many ways introduce bugs.
What you need to do is set default state in reducer which is later updated by request response and pass it down as a props to your component.
Also, check out this answer by one of the redux-observable authors.
By the way is there any reason why you Axios instead AjaxObservable

React Redux best practices for performing actions

Where should I perform actions (redirecting or adding/removing something to/in the localstorage) in React (and Redux)? So after the password is successfully updated I want to redirect the user to another page. Should I redirect after the dispatch method, should I do it in the component or are there other options?
Example action:
export function updateAccountPassword(encryptedPassword) {
return dispatch => {
axios.post(API_URL + '/account/recovery/update', {
_id: getSignedInUserID(),
password: encryptedPassword
}).then(() => {
dispatch(updateUserPasswordSuccess())
}).catch(() => {
dispatch(updateUserPasswordFailError());
})
}
}
function updateUserPasswordSuccess() {
return({
type: RECOVERY_UPDATE_SUCCESS
})
}
function updateUserPasswordFailError() {
return({
type: RECOVERY_UPDATE_FAIL_ERROR,
payload: 'Something went wrong, please try again'
})
}
The way I am doing it is by passing the this.props.history.push as a callback to the action creator, and calling it, as you suggested, in the action creator, after dispatch.
Here is an example from my code:
In the component form's submission, calling the action creator:
this.props.ACTION_CREATOR(formPayload, () => {
this.props.history.push(`ROUTING_TARGET`);
});
And, then, in the action creator, when the proper condition has been met, calling the callback (rerouting).

How to show a message after Redux dispatch

When a button is clicked I call the following:
this.props.dispatch(addNote(this.state.noteContent))
This in turn calls the following action:
export default function addNote(note){
return dispatch => {
axios.post('http://localhost:2403/notes', {
Body: note
})
.then(function (response) {
dispatch({
type: ADD_NOTE,
payload: response.data
})
})
.catch(function (error) {
console.log(error)
})
}
}
My reducer then updates the state and a new note is added to the list, so it's all working correctly.
However I now want to show a message in the UI which says "Note has been added successfully". Ideally, this would be a part of a wider notifications system, but for now, I just need to figure out how to report success (or failure) on this one action.
How do I achieve this?
You can return a promise from your dispatch using redux-thunk, why not use that? Try this code in your thunk:
export default function addNote(note){
return dispatch => {
return axios.post('http://localhost:2403/notes', {
Body: note
})
... //function continues
Then you can do:
this.props.dispatch(addNote(this.state.noteContent)).then(successFunc, failureFunc);
successFunc = function() {
//Show message on UI
}
You can use a toast component (like this https://www.npmjs.com/package/react-toastify) that sits on top of your routes in your app that renders every time an action in redux is called.
In each of your action functions, you can have a call to a message reducer that updates the state inside message reducer. Each time the state in that reducer is changed, the toast component will re-render and last for a certain amount of time or until a user manually closes the toast component.

React-redux cross access state value

For last two weeks I have been working with redux and I'm facing an issue where I want to access/change a state value of another reducer. How can I achieve that?
For example: I have two components 'A-Component' and 'Message-component'
which has 'A-actions', 'Message-actions' and 'A-reducer', 'Message-reducer' respectively
When an action of 'A-Component' is called it will call the corresponding reducer function where I need to update the Message-reducer state value which will display the message box
A-action
export function add(data) {
return {
types: [types.ONADD, types.ONADDSUCCESS, types.ONADDFAIL],
payload: {
response: api.add(data).then(response => response),
data
}
};
}
A-reducer
export default createReducer(initialState, {
[types.ONADD](state) {
return {
...state,
message: 'Updating Records'
};
}
});
The above mentioned message state value is message reducer's state value. I want to update the message state value from A-reducer
which in turn updates the message component. Is this possible in redux?
I tried with various middleware but failed.
Thank in advance!
I think you're approaching this the wrong way. You should normalize your data as much as you can, and then maybe use the connect decorator to compose the state you need for your UI. For example, Messages could be nested under a "Friend"'s node, but it's better to have them in their own store, and then make a function that selects the messages from a friend based on a relationship. This gives you aggregations (You have 3 unread messages) for free. Take a look at reselect for a way to do this in a nice (and cached) way.
Edit:
You could write middleware which dispatches multiple actions:
export default (store) => (next) => (action) => {
if(!action.types){
return next(action);
}
action.types.forEach(type => {
next({
type,
payload: action.payload
})
});
}
Then call it from an Action Creator like so:
export function addMessage(message){
return {
types: ['ADD_MESSAGE', 'UPDATE_USER'],
payload: message
}
}
If you already have a update action in Message-actions
I think you can just directly dispatch the update action when ONADDSUCCESS is triggered.
// Message action
export function MessageUpdate (data) {
return {
type: ...,
data,
}
}
// A action
export function add(data) {
return dispatch => {
dispatch({
type: types.ONADD
});
// code for your add event
api.add(data).then( response => {
(() => {
dispatch(MessageUpdate(response));
return dispatch({
type: types.ONADDSUCCESS,
})
})()
});
}
}
Hope this answer to your question.

Resources