I am learning Redux in React. I am using redux-thunk. I have an action like below
export const login = (value, history) => dispatch => {
Axios.post('/api/users/login', value)
.then(response => {
dispatch(getAddress()); // I am calling like this
})
.catch(error => {});
}
My address action is like below
export const getAddress = () => dispatch => {
Axios.get('/api/address')
.then(response => {
dispatch({
type: 'getAddresses',
payload: response.data
});
})
.catch(function (error) {});
}
I am trying to display value in my component like below
render() {
return (
<div>Hello {console.log(this.props)}</div> // I am getting empty object
);
}
const mapStateToProps = state => ({
addresses: state.address
});
export default connect(mapStateToProps)(Dashboard);
But I am getting empty Object.
I would like to redirect user to dashboard after login where the addresses will display. How can I do that ?
Redux thunk middleware allows to chain via dispatch, dispatch(...) returns dispatched action, i.e. a promise if promise chains weren't broken:
export const login = (value, history) => dispatch => {
return Axios.post('/api/users/login', value) // return!
.then(response => {
return dispatch(getAddress()); // return!
})
.catch(error => {});
}
export const getAddress = () => dispatch => {
return Axios.get('/api/address') // return!
.then(response => {
return dispatch({ // return!
type: 'getAddresses',
payload: response.data
});
})
.catch(function (error) {});
}
Initial action should be dispatched somewhere. In vanilla Redux setup, it could be dispatched after store definition:
store.dispatch(login());
In React Redux setup, components are integral parts of Redux data flow. Asynchronous thunk is a side effect and it should be dispatched once in componentDidMount. In case of initial action, it should be dispatched in parent component:
@connect()
class App extends Component {
componentDidMount() {
return this.props.dispatch(login());
}
render() {
return !this.props.addresses ? 'Loading' : <Dashboard />
}
}
Here is a demo.
So this needs a very basic introduction to the flow of Redux with 'side effects'.
Definition alert! In Redux stuff like calls to APIs are called side effects. This is because you are doing something outside the typical unidirectional data flow.

Hope you have understood this flow. I'm specifically concerned about a specific part that you seem to be confused about. So in your code you have tried to do this.
then(response => {
return dispatch(getAddress());
})
What your code is trying to do here is that, it's trying to 'dispatch' a side effect. This is wrong!
Dispatch is almost always a plain old JS object which is serializable. Typically you will have stereotypical structure like this. Which you seem to have in your other get address call.
{
type: 'GET_ADDRESS_REQUEST_SUCCESS',
payload: {}
}
So the proper way to approach your task is like this. Think of dispatching actions like emitting signals when various things happen.
export const login = (value, history) => dispatch => {
Axios.post('/api/users/login', value)
.then(response => {
//Send out a success signal
dispatch({
type: 'loginSuccess',
payload: response.data
});
//Now that I have logged in successfully I can call for my address
//This is simply how you call an action within an action!
getAddress();
}).catch(error => {
//login failed signal
dispatch({
type: 'loginFailed',
payload: response
}); // I am calling like this
});
}
export const getAddress = () => dispatch => {
Axios.get('/api/address')
.then(response => {
//Get address success signal
dispatch({
type: 'getAddressSuccess',
payload: response.data
});
}).catch(function (error) {
//Get addresses failed signal
dispatch({
type: 'getAddressFailed',
payload: error
});
});
}
The next important part is the reducer, which you have not included here! If actions emits signals think of the reducers as a receiver which receives and processes this signal. A reducer will update the existing state based on the action deployed.
export default function appReducer(state, action) {
switch (action.type) {
case 'getAddressSuccess': //Waiting on the signal!
return Object.assign({},state,{address : action.payload}
//Set the proper address based on your payload from the api call
default:
return state
}
}
You also should have setup your redux thunk configuration properly for this to fully work. Cheers!
============EDIT=============
So upon checking the codebase, you have used the combine reducer to meld multiple reducers together.
import { combineReducers } from 'redux';
import authReducer from './authReducer';
import addressReducer from './addressReducer';
const rootReducer = combineReducers({
authReducer,
addressReducer
});
export default rootReducer;
So in mapsStateToProps your store state will look like this
{
authReducer: {
// state managed by the authReducer
},
addressReducer: {
address: 'Test Streat, London'
}
}
So change your mapStateToProps to look like this
const mapStateToProps = state => ({
addresses: state.addressReducer.address
});
export default connect(mapStateToProps)(Dashboard);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With