Calling action from async action in react-redux - javascript

This is my file for action creators in my react app.
Inside my async getHomePage action I am trying to call setLoading() action which is not getting called. When I comment my code below in my try block and only keep setLoading() then it works and I can see setLoading called in redux dev tools. But when I keep my whole code it gives me SET_HOME and not SET_LOADING.
Is there something I am doing wrong by calling another action from async action.
import axios from '../axios/default.instance';
import {
SET_LOADING,
SET_HOME
} from './types';
export const getHomePage = () => async dispatch => {
try {
setLoading();
const result = await axios.get("/home");
dispatch({
type:SET_HOME,
payload: result.data
});
} catch (error) {
console.log(error);
}
};
export const setLoading = () => {
return {
type: SET_LOADING
}
}

Related

Dispatch outside component

I want to dispatch outside component. I want to use option 2 from this link [https://daveceddia.com/access-redux-store-outside-react/][1]. My code look like this
const loginUser = async (data) => {
return axios.get(url + "/sanctum/csrf-cookie").then(() => {
axios.post(url + '/api/login', data)
.then(res => {
return res.data
})
.catch((err) => {
console.log(err);
})
})
}
export const handleLogin = (data) => async (dispatch) => {
console.log('test');
try {
const user = await loginUser(data);
dispatch(actions.setUser(user));
} catch (err) {
console.log(err);
}
}
And into my component
const test = (e) => {
e.preventDefault;
handleLogin({email: 'test#test.pl', password: 'password'})
}
return (
<div className="container">
<h2>Login</h2>
<form onSubmit={handleSubmit(test)}>
//...
It doesn't finish code and it may contain mistakes but currently the most important for me is why this code doesn't work and if sometimes is wrong why doesn't show any error. I think that problem is in sync(dispatch). In this example I add console.log for test and it wasn't display. Without that function display console.log.
Redux thunk is added to the store too
const store = createStore(allReducers, composeWithDevTools(applyMiddleware(thunk)))
import store and use like this :
store.dispatch(actions.setUser(user));
and you can get state out of component with :
store.getState().items
you did not dispatch your actions in your component and in your action js .
you can call an action in component by props and dispatch and I could not see the props so I use useDispatch and call handleLogin action there.
use this in action.js file:
const user = await loginUser(data)(dispatch);
instead :
const user = await loginUser(data);
then in component:
import {useDispatch} from "react-redux";
const dispatch = useDispatch();
const test = (e) => {
e.preventDefault;
dispatch(handleLogin({email: 'test#test.pl', password: 'password'}))
}

how to solve this : Actions must be plain objects. Use custom middleware for async actions

I'm trying to clone one of MERN stack project called Emaily But I'm facing an error
Error: Actions must be plain objects. Use custom middleware for async actions.
My Action is given bellow ,
import axios from 'axios';
import { FETCH_USER, FETCH_SURVEYS } from './types';
export const fetchUser = () => async dispatch => {
const res = await axios.get('/api/current_user');
dispatch({ type: FETCH_USER, payload: res.data });
};
You should remove async keyword from dispatch.
export const loadUsers = () => dispatch => { dispatch({ type: LOAD_USERS_LOADING });

Redux validation before dispatching axios call

Im trying to pass a validation test before making an axios call, but not sure how to implement it correctly its either validation or sending request straight away.
In my main container named "main.jsx" i have
const mapDispatchToProps = dispatch => {
return {
sendRequest: (query) => dispatch(request_house(query))
};
};
and then in my actions
import * as actionTypes from './actionTypes'
import serverConnect from "../../axios/connection";
export const set_house = (response) =>{
return {
type: actionTypes.SET_HOUSE,
response,
}
}
export const set_error = () =>{
return {
type: actionTypes.SET_ERROR
}
}
export const validate_request = (query) =>{
return {
type: actionTypes.VALIDATE_REQUEST,
query
}
}
export const request_house = (query) =>{
return dispatch =>{
serverConnect.post(`/searchHouse/${query}`).then(response => {
dispatch(set_house(response))
}).catch(()=>{
dispatch(set_error)
});
}
}
Is there a way to dispatch validation call before making a request? how should i approach this?
Redux doesn't support chaining of actions. That's where Redux-Thunk, Redux-Saga and other libraries come in to picture.
Check this blog, which explain in detail about doing chaining or asynchronous operations with different libraries.

response undefined using then for async redux api call?

How to properly redirect user using the response of the api call in redux? I need the resp after axios's then but I got undefined, although I've returned the thunk in my action
//jobForm.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { createJob } from '~/actions/jobAction'
import { getUserId } from '~/utils'
import moment from 'moment'
#connect(state=>state.job,{createJob})
class Form extends Component {
handleSubmitForm = () => {
this.props.createJob({formData})
.then(resp => console.log(resp)) //undefined?)
}
//etc..
}
export default Form
//action
export function createJob(params) {
return dispatch=>{
dispatch({type: CREATING_JOB})
return axios.post(`/job/create`, {...params})
.then(res=>{
if(res.status===200 && res.data.status===1){
dispatch({
type: CREATE_JOB,
payload: res.data.data
})
}
})
.catch(res => {
dispatch(errorMsg(res.data.msg))
})
}
}
I can pass my payload to reducer but I need a response's id to redirect the user to a created job page.
You're not returning anything after processing the API call, which is why the promise resolves to "undefined". For the promise to resolve with data, you'll need to return the id after dispatching the action. See below.
export function createJob(params) {
return dispatch=>{
dispatch({type: CREATING_JOB})
return axios.post(`/job/create`, {...params})
.then(res=>{
if(res.status===200 && res.data.status===1){
dispatch({
type: CREATE_JOB,
payload: res.data.data
});
// RETURN ID AFTER DISPATCHING ACTION
return res.data.data
}
})
.catch(res => {
dispatch(errorMsg(res.data.msg))
})
}
}
An alternative approach, that is arguably more inline with the flux one-way data flow paradigm would be to perform the redirect based on a change in the redux state rather than completion of the action.
You could use componentWillReceiveProps to determine if the new job has been created, if so, redirect
componentWillReceiveProps(nextProps) {
// use nextProps to determine if the new job has been added
// to the job state
// ...
const isNewJobAdded = nextProps.job.includes(...)
if (isNewJobAdded) {
// perform redirect
...
}
}

Thunk Action Body not being Invoked

My thunk action doesn't seem to be running through its core logic. I tall the thunk action from componentDidMount but it doesn't in turn cause this to run: const response = await findOne(id).
Also, I thought I didn't need to explicitely pass dispatch as a prop to mapDispatchToProps if using redux-thunk, I thought that the way I have my thunk setup is that dispatch is available already to the thunk? And I've used other actions like this and it's worked fine, why not this one?
Thunk Action
export function fetchCompany(id) {
return async (dispatch) => {
try {
const response = await findOne(id)
if(response && response.body) {
const company = response.body
dispatch(companyReceived(company))
}
} catch(err) {
console.log("failed request in authenticate thunk action")
console.log(`error details: ${err.status} /n ${err}`)
}
}
}
Container
......
import { fetchCompany } from '../../client/actions/company/CompanyAsyncActions'
class InterviewContainer extends Component {
async componentDidMount() {
await fetchCompany(this.props.params.companyId)
}
render(){
return (this.props.company && <Interview className='ft-interview' company={this.props.company} />)
}
}
const mapStateToProps = state => ({
company: state.company.company
})
const mapDispatchToProps = {
fetchCompany: fetchCompany
}
export default connect(mapStateToProps, mapDispatchToProps)(InterviewContainer)
In the past, I haven't passed (dispatch) as a prop to mapDispatchToProps and it worked fine. But I see everyone else is doing so. How was my code working in the past if I wasn't doing that? And why isn't this working this time around in the example above?
Taking a look at another async action thunk container and call example, this is working completely fine, and I'm calling it the same way in another container
container
class HomePageContainer extends Component {
constructor(){
super()
}
async componentDidMount() {
await this.props.fetchFeaturedCompanies()
await this.props.fetchCompanies()
await this.props.fetchCountries()
}
render(){
return (<HomePage className='ft-homepage'
featuredCompanies={this.props.featuredCompanies}
countries={this.props.countries}
companies={this.props.companies}
/>)
}
}
const mapStateToProps = state => ({
countries: state.country.countries,
companies: state.company.companies,
featuredCompanies: state.company.featuredCompanies
})
const mapDispatchToProps = {
fetchCountries: fetchCountries,
fetchCompanies: fetchCompanies,
fetchFeaturedCompanies: fetchFeaturedCompanies
}
export default connect(mapStateToProps, mapDispatchToProps)(HomePageContainer)
thunk action
export function fetchCompanies() {
return async (dispatch, getState) => {
const response = await find()
if(response && response.body) {
const companies = response.body
dispatch(companiesReceived(companies))
}
}
}
In componentDidMount of InterviewContainer you're accidentally calling the imported fetchCompany, instead of this.props.fetchCompany.

Categories