2
votes

I can't figure how to make a post request with axios and redux-thunk so the action is dispatched after the query.

Here's my request module

export default {
    get: function (action, url) {
        return (dispatch) => {
            axios.get(`${ROOT_URL}${url}`)
                .then(({ data }) => {
                    dispatch({
                        type: action,
                        payload: data
                    });
                });
        };
    },

    post: function (action, url, props) {
        return (dispatch) => {
            axios.post(`${ROOT_URL}${url}`, props)
                .then(({ data }) => {
                    return (dispatch) => {
                        dispatch({
                            type: action,
                            payload: data
                        });
                    };
                });
        };

    }
} 

The GET works. When I call the post function, it enters the function, but never run the returned function.

I tried modifying the order of the functions. I ended up with a working post request, but the action was never dispatched.

post: function (action, url, props) {
        //POST works but action is not dispatched to reducer
        axios.post(`${ROOT_URL}${url}`, props)
            .then(({ data }) => {
                return (dispatch) => {
                    dispatch({
                        type: action,
                        payload: data
                    });
                };
            });
    }

Any idea how I can achieve a working post request that gets send to my api and then the response is dispatched to the reducer?

Thank you!

UPDATE

After extensive testing and back and forth, I think the problem is in redux-form. As pointed by Michael, the dispatch should work. I tested my call in my component with the get method and it doesn't work. Here's my component

const form = reduxForm({
    form: 'LoginPage',
    validate
});

const renderField = ({ input, label, type, meta: { touched, error } }) => (
    <div className="form-group">
        <label>{label}</label>
        <div>
            <input {...input} placeholder={label} type={type} className="form-control" />
            {touched && ((error && <span>{error}</span>))}
        </div>
    </div>
)

class LoginPage extends Component {
    displayName: 'LoginPage';

    onSubmit(props) {
        login(props.email, props.password);
    }

    render() {

        const {handleSubmit} = this.props;

        return (
            <div className='row'>
                <div className='center-block'>
                    <form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
                        <Field name="email" type="email" label='Courriel :' component={renderField} />

                        <Field name="password" type="password" label='Mot de passe :' component={renderField} />

                        <div className="form-group text-center">
                            <button type="submit" className='btn btn-primary'>Se connecter</button>
                        </div>
                    </form >
                </div>
            </div>
        );
    };
};

const validate = values => {
    const errors = {}
    if (!values.email) {
        errors.email = 'Required'
    } else if (!/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)) {
        errors.email = 'Invalid email address'
    }
    if (!values.password) {
        errors.password = 'Required'
    } 4
    return errors
}

export default reduxForm({
    form: 'LoginPage',
    validate
})(LoginPage);

The post request is in the onSubmit method. The login method is called but the return value is never dispatched.

Again, thank you for your time and help

3

3 Answers

4
votes

I found my problem. Thanks to Michael for his comment that helped me look in another direction.

The problem was that my form wasn't connected to redux. I ended up adding the connect function to my export statement.

export default connect(null, { login })
    (reduxForm({
        form: 'LoginPage',
        validate
    })(LoginPage));

And I also had to change the call to the login function in onSubmit

 onSubmit(props) {
        this.props.login(props.email, props.password);
    }
2
votes

Can't add a comment, but I'm glad you figured it out. I'd like to warn you however that on newer versions of redux-form you'll have to decorate your form outside of the connect function to redux. I ran into this problem and it drove me nuts trying to figure it out.

it would be a two step process to connect redux-form after the update. for example, it would look like this.

LoginPage = reduxForm({form: 'LoginPage', validate})(LoginPage)

and then afterwards your standard connect function

export default connect(null, actions)(LoginPage)

hope this saves you the headache in the future

0
votes

your function shouldnt 'return (dispatch)' again, because what the action does is return a function. it should just be

function myFunc(action, url) {
 return function (dispatch) {
   axios.post(`${ROOT_URL}${url}`, props)
    .then(response => {
      dispatch({
        type: action,
        payload: response.data
      })
  })
  }
}

edited with full function.