0

Hello wonderful people at Stack overflow. I have a question that I've been trying to solve for the past few hours. For some it might be super basic, but for me (a complete noob at Redux and React) it's like solving the Palestine conflict. However...

In my React, Redux application I want the user to be able to log in. I don't know if I needed to add Redux to my React app when wanting to implement a login feature, but after watching a lot of videos and reading a bunch of stuff I was sure that I needed to do it (because it looks hardcore af yo).

So, I'm using Redux-form to let the user type in email and password:

LoginForm.js:

import React from 'react'
import { Field, reduxForm } from 'redux-form'

const LoginForm = ({ handleSubmit }) => {
  return (
    <form onSubmit={handleSubmit}>
      <div>
        <label>Email:</label>
        <Field name="email" component="input" type="text" />
      </div>
      <div>
        <label>Lösenord:</label>
        <Field name="password" component="input" type="password" />
      </div>
      <button type="submit">Submit</button>
    </form>
  )
}

export default reduxForm({
  form: 'login'
})(LoginForm)

Everything here works, because it's basically a ripoff from their docs hehe.. But! In my LoginContainer.js is where everything turns into cr*p:

LoginContainer.js:

import React, { Component } from 'react'
import { login } from '../../actions/login'
import LoginForm from './Views/LoginForm'
import { connect } from 'react-redux'

class LoginContainer extends Component {
  submit(values) {
    this.props.login(values)
  }

  render() {
    return (
      <div>
        <h1>hejsan</h1>
        <LoginForm onSubmit={this.submit.bind(this)} />
      </div>
    )
  }
}

function mapStateToProps(state) {
  return { auth: state.auth }
}

export default connect(mapStateToProps, login)(LoginContainer)

As you might see I'm importing an action called login (source code further down), I'm importing my form and the last part I'm little uncertain about.

Here's my *login.js-action.

login.js:

import axios from 'axios'
import settings from '../settings'

axios.defaults.baseURL = settings.hostname

export const login = data => {
  return dispatch => {}
}

Very cr*ppy action I know.

But what I want to be able to do is; when I press the button I'd like to see a POST (404) request in my console. Sorry if this is a sh*tty question, and it's more like a cry for help by the way. But when you have been desperately been trying to make this work you'll start doing desperate things.

Hopefully someone can guide me here, it will be greatly appreciated. Thanks for reading.

1 Answer 1

1

In this case you are returning a thunk from your action creator (meaning your action creator returns a function). To enable this behavior you need to assign some special middleware to your store. The most common solution is redux-thunk.

Then, you have a few options:

If you want to keep track of loading state in your store (not typically necessary) you would dispatch a loading action from within your login action creator

const setLoginLoading = value => ({
  loginLoading: true
})

const setLoginData = data => ({
  loginData: data
})

const login = data => dispatch => {
  dispatch(setLoadingValue(true))
  // or your preferred promise enabled http lib
  // you should also handle errors here
  return fetch('/login', { method: 'POST', body: data })
    .then(res => res.json())
    .then(res => {
      dispatch(setLoginData(res))
      dispatch(setLoadingValue(false))
      return res
    })
}

If you don't care about keeping the loading / error states in your store, you can simply dispatch the action from your component the same way you're doing now. If you return a promise in your action creator, it will get returned by the dispatcher as well.

submit(values) {
  this.props.login(values)
    .then( // etc
}

You can then simply keep the loading / error states in this component's state (using setState).

Sign up to request clarification or add additional context in comments.

5 Comments

Hey Ricardo! Thanks for taking your time to answer my question. I actually have this in my store.js: const middlewares = [promiseMiddleware(), thunk, createLogger()]. But one thing I noticed after publishing my question React is telling me that; TypeError: this.props.login is not a function in my LoginContainer.js file.
Ah, yes. That's because your mapDispatchToProps setup is incorrect. From here mapDispatchToProps can be 1 of 2 things 1) an object that maps functions to props, where each function gets bound to a corresponding action creator or 2) a function that accepts dispatch and own props as arguments and returns an object of new props.
(Not enough room on the previous comment) Instead of export default connect(mapStateToProps, login)(LoginContainer) you should have export default connect(mapStateToProps, { login })(LoginContainer)
Well that was an awkward miss hehe... But now that my function is working, I should be able to make a POST request to my API, correct?
Yes, you can put any sort of javascript logic in your action creator and dispatch other actions using the dispatch function passed by redux-thunk. As an aside, since you said that you're a "noob" at react, I would recommend simply making the http request directly in your component and not worry too much about redux until you understand the basics. Just my 2c. Good luck!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.