Using redux-thunk in react-native with async dispatch - javascript

I have redux-thunk set up in my react-native code.
In mapDispatchToProps I have:
const mapDispatchToProps = dispatch => {
return {
login: (state, navigator) => dispatch({
type: "USER",
payload: loginFunc(state, navigator)
}),
}'
}
The login function is a firebase function that returns a promise chain that eventually returns the object I need.
However, in my reducer it looks like my payload is a promise or some funky object.
It looks like:
{
a: someVal,
b: sommeOtherVal,
c: someMoreVal,
...ValsUpToI.
i: {
// The values I actually need show up
}
This messes me up because when I try to do payload.myValue I get undefined in my redux state. I don't think it is safe to just do payload.i either because this is probably some promise or async issue right? That i could very well be something else later?

Use asynchronous actions approach to execute promise based function API calls as mentioned in redux documentation.
const mapDispatchToProps = dispatch => {
return {
login: (state, navigator) => {
return loginFunc(state, navigator).then(
response => dispatch({
type: "USER",
payload: response
}),
error => console.log('An error occurred.', error)
)
}
}
That way you can call promise based function and utilize response or error correctly.

Related

How to clear local state after dispatching a success action in redux saga?

Im trying to clear my component state after a successful call in redux saga. How do I do it?
Im trying to use the component state for my input value
this.state = {
department: '',
};
My current solution looks like this;
add(department).then(action => {
if(action.type.endsWith('SUCCESS')) {
this.setState({department: ''})
}
})
Im trying to clear my input after a success call in saga.
The approach i usually take with this is to have the saga update a value in the redux store, and have the component check for that change. This may include running some code in componentDidUpdate.
If you'd like to avoid adding things to the store, i can think of another possibility, albeit a bit of a combersome one: you could create a promise and pass its resolve and reject methods as part of the action you dispatch. Then in the saga, it could call those to resolve the promise. For example:
export function* addDepartment(action) {
const { department, resolve, reject } = action;
try {
// do something async with department
resolve();
} catch (ex) {
reject(ex);
}
}
To be used in the component's mapDispatchToProps like this:
const mapDispatchToProps = (dispatch) => ({
add: (department) => {
return new Promise((resolve, reject) => {
dispatch({ type: 'ADD', department, resolve, reject });
});
}
});
... and in the component proper like this:
this.props.add('some department')
.then(() => this.setState({ department: '' })
.catch((err) => console.log('an error occurred', err));

React Native: Possible Unhandled Promise Rejection (id: 0): TypeError: undefined is not an object

I have a React Native application that I cloned and after registering into the app on my simulator, I get this yellow error at the bottom of the screen which says:
Possible Unhandled Promise Rejection (id: 0): TypeError: undefined is
not an object (evaluating 'data.Items')
I believe it has to be referencing one or all of these action creators in this file:
export function fetchPrefences({Key}) {
return dispatch => {
const url = `${endpoints.v2.INDIVIDUALS}/${Key}/preferences`;
requester.sendGet(url).then(data => {
const payload = helpers.sortPreferences(data);
dispatch({
type: types.SET_USER_PREFERENCES,
payload,
});
});
};
}
export function fetchTopics() {
return dispatch => {
requester.sendGet(endpoints.TOPICS_OF_CONCERN).then(data => {
dispatch({
type: types.SET_USER_TOPICS,
payload: data.Items,
});
});
};
}
export function handleUpdateTopics({topics, involved}, updateBoth = false) {
return dispatch => {
return requester
.sendPut(endpoints.TOPICS_OF_CONCERN, {
Items: topics,
})
.then(data => {
dispatch({
type: types.SET_USER_TOPICS,
payload: data.Items,
});
if (updateBoth) {
dispatch(handleUpdatePreferences({involved}));
}
});
};
}
I have written asynchronous action creators in the past, but I can't see what is wrong with these. Is it that data is undefined? If so, my question would be, how is this possible if in other areas of the application data is being used with no obvious errors?
Your data result is undefined ... it has nothing todo with your redux action
One easy and straight forward way to check your api-endpoint is postman ...

Return a promise for a simple action creator in react using react-redux

I am new to the react-redux . Here , I think this is a very basic question. But , I have a action creator, and I am using a redux thunk.
export const updateActivePage = (activePage) => {
return {
type: UPDATE_ACTIVEPAGE,
payload: activePage
}
}
what I tried is
export const updateActivePage = (activePage) => (dispatch) => {
return new Promise( function(resolve, reject) {
dispatch({
type: UPDATE_ACTIVEPAGE,
payload: activePage
})
})
}
the function after then is not getting called.
Now, in my componentdidmount In want to use .then after this
So, for that I want to return a promise . So,How can I do this ? I am using the reux-thunk
Straight from redux-thunk readme:
function makeASandwichWithSecretSauce(forPerson) {
// We can invert control here by returning a function - the "thunk".
// When this function is passed to `dispatch`, the thunk middleware will intercept it,
// and call it with `dispatch` and `getState` as arguments.
// This gives the thunk function the ability to run some logic, and still interact with the store.
return function (dispatch) {
return fetchSecretSauce().then(
sauce => dispatch(makeASandwich(forPerson, sauce)),
error => dispatch(apologize('The Sandwich Shop', forPerson, error))
);
};
}
...
// It even takes care to return the thunk’s return value
// from the dispatch, so I can chain Promises as long as I return them.
store.dispatch(
makeASandwichWithSecretSauce('My partner')
).then(() => {
console.log('Done!');
});
Promises are rather used when you want to fetch some data from external source (like REST). However, if you really want to do this, a action creator has to return a function:
export const updateActivePage = (activePage) => {
return (dispatch) => {
return dispatch ({
type: UPDATE_ACTIVEPAGE,
payload: activePage
});
}
}
Something like this should return promise.
However, this promise will be resolved when action is dispatched. It's not the same as redux state change. I think that you don't really want to use promise here.
If you want to react when something in redux state changes, your component should observe the state (using mapStateToProps) and you can handle changes in componentWillUpdate method.

Why does an awaited Redux action creator not await properly? (React Native)

In my React Native app, I have an action creator that dispatches an action to update the state in the Redux store. I call this action creator with 'await' and then do a setState(), but I noticed the Redux store is getting updated AFTER the setState is completed. My code looks like this:
updateFunction = async () => {
await this.props.actionCreator1();
this.setState({property1: this.props.property1});
}
I 'await'ed the action dispatch because I need the store to be updated before I setState(). I must be misunderstanding what gets returned etc when you dispatch an action, because the store does not get updated until after setState() runs. Can anyone explain why this could occur?
Thanks!
UPDATE
This is how I bind my Redux store to my component
const Component1 = connect(
state => ({
property1: state.Reducer1.property1
}),
dispatch => bindActionCreators({
actionCreator1: ActionCreators.actionCreator1
}, dispatch)
)(Component1)
This is where I create the action creator in actions.js
export const ActionCreators = {
actionCreator1: () => ({type: 'actionCreator1', property1: 'value'})
}
This is where I reduce the actions in reducer.js
const initialState = {
property1: undefined
}
export default (state = initialState, action) {
switch(action.type) {
case('actionCreator1'): {
return {
...state,
property1: action.property1
}
}
}
}
You are not supposed to use await on a function that doesn't return a Promise, to make it work either you can wrap your action creator so that it returns a promise then resolves to the value you want, or do a different approach not relying on async-await.
You can define your action creator like below:
export const ActionCreators = {
actionCreator1: () => new Promise(function (resolve, reject) {
return resolve({type: 'actionCreator1', property1: 'value'})
});
}
It will work if you added redux-thunk middle ware.
I'm not sure you are using React/Redux best practices. You are using action which changes the redux state but at the same time you are trying to use setState which updates the state of React. Moreover, your code does not execute how you expect it because your await function is not promise based.
This does implicitly responds to your question. Take the functions below as an example:
function something1(){
setTimeout(() => console.log('before'), 2000);
}
function something2(){
var result = new Promise(resolve => setTimeout(() => resolve(console.log('before')) ,2000));
return result;
}
function el(){
console.log('after')
}
updateFunction = async () => {
await something1(); // await something2();
el();
return 'done';
};
and try first to run updateFunction() in your console. Because function something1() is not promise based you will see that it will not await and the string 'after' will be printed first. Now inside your updateFunction() try to change await something1() with something2() in your console again. You will see that the rest of the el() function will await for function something2() to finish first and your console will print out the strings 'before' and then 'after'. Hope this clarifies things a bit.

How do async redux functions work?

I started learning redux in reactjs. I am trying to implement an async structure to redux but I am really confused...
To implement an async function and use the promise you should type async before your function and use await before using the promise.
But in many examples I never saw they use of async before functions and await before the promise variables.
For example look at these two links:
https://redux.js.org/advanced/async-actions
https://github.com/reduxjs/redux/tree/master/examples/async
So how can I call async function in the reducer and return the async results?
For example, I want to prepare this list with an async function and get the list with axios or fetch API :
const list = [
{id: 1, title: 'One'},
{id: 2, title: 'Two'},
{id: 3, title: 'Three'}
]
export function newsReducer(state = [], action) {
switch (action.type) {
case 'GET_NEWS':
return list
default:
return state
}
}
To summarize it I would suggest, to understand this concepts action, reducer and store.
An action is a trigger for one or more reducer cases
the store is on and all the data is contained and only reduceres can change it using the method they get from the store 'dispatch'
reducer is a piece of code that produces immutable changes on the store.
So in order to do a change to the store synchronically you have to call the store method dispatch such that the reducer triggers and changes what you expect.
To do async you will have to call the reducere when the async call is done.
Example:
// action method called by react component when user submits changes
export function updateProduct(product) {
// returns a function since this method has to be called also with dispatch() in the component
return dispatch => {
// trigger first store change
dispatch({ type: PRODUCT_EDIT.PRODUCT_EDIT_REQUEST });
// trigger secod store change and mark the async call, updateProduct is ASYNC
ProductsService.updateProduct(product)
.then(
res => {
dispatch({ type: PRODUCT_EDIT.PRODUCT_EDIT_SUCCESS, data: res.data });
dispatch(successNotification('Product updated'));
},
error => {
dispatch({ type: PRODUCT_EDIT.PRODUCT_EDIT_FAILURE, data: error.response.data });
dispatch(errorNotification(error.response.data));
}
);
};
}
Other tutorials I think you should check:
https://medium.com/#rajaraodv/step-by-step-guide-to-building-react-redux-apps-using-mocks-48ca0f47f9a
One way to do it is to use redux-thunk like # Sujit.Warrier suggested in the comment here is a small and simple example that can get you started using redux-thunk.
export const getlist =()=> dispatch =>{
fetch(`api link for your list`).then(res => res.json())
.then(data => {
dispatch({type:'GET_NEWS' , payload:data})
});
};
and then you can dispatch the function in your component

Categories

Resources