1
votes

I have a function that returns a redux thunk async function. The problem is it isn't firing. The createUser function is running because the first console.log statement inside it is running but the one inside the redux thunk function is not. I'm not entirely sure why? Any ideas for things I can try? This same good was working on my react-native app so not sure why it's not working here.

Here is the createUser function.

export function createUser (userData) {

  console.log('Getting here?')

  return function (dispatch, getState) {
    dispatch(authenticating());

    console.log('But are you getting heeeere?')

    const email = userData.email;
    const password = userData.password;

    firebaseAuth.createUserWithEmailAndPassword(email, password).catch((error) => {
      // Handle Errors here.
      var errorCode = error.code;
      var errorMessage = error.message;
      console.log(errorMessage);
    }).then(() => {
      const user = firebaseAuth.currentUser;

      db.ref('/users/' + user.uid).set({
        username: userData.username,
        displayName: userData.displayName,
        uid: user.uid
      })
      dispatch(isAuthed());

    }).catch((error) => {
      console.warn('Error in createUser callback', error)
    });
  }
}

And my setup

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import { App } from '~/components/App';
import registerServiceWorker from './registerServiceWorker';
import * as reducers from '~/redux';
import './index.css';

const store = createStore(
  combineReducers(reducers),
  applyMiddleware(thunk)
)

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root'));
registerServiceWorker();

Finally, here is the SignUp component where I dispatch.

import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { createUser } from '~/redux/modules/authentication';
import './SignUp.css';

class SignUp extends Component {
  static propTypes = {
    dispatch: PropTypes.func.isRequired
  }
  constructor(props) {
    super(props);

    this.state = {
      username: '',
      displayName: '',
      email: '',
      password: '',
      confirmPasswordText: ''
    }
  }
  handleUsernameChange = (event) => {
    this.setState({username: event.target.value});
  }
  handleDisplayNameChange = (event) => {
    this.setState({displayName: event.target.value});
  }
  handleEmailChange = (event) => {
    this.setState({email: event.target.value});
  }
  handlePasswordChange = (event) => {
    this.setState({password: event.target.value});
  }
  handleConfirmPasswordChange = (event) => {
    this.setState({confirmPasswordText: event.target.value});
  }
  stopDefault = (event) => {
    event.preventDefault();
    createUser(this.state);
  }
  render () {
    return (
      <div className="sign-up">
        <div>
          <h1>Nimbus</h1>
        </div>
        <form onSubmit={this.props.dispatch(this.stopDefault())}>
          <div className="form-group">
            <label>Username</label>
            <input
              type="text"
              className="sign-up__input form-control"
              id="formGroupExampleInput"
              placeholder="Choose a username"
              onChange={this.handleUsernameChange}
            />
          </div>
          <div className="form-group">
            <label>Display Name</label>
            <input
              type="text"
              className="sign-up__input form-control"
              id="formGroupExampleInput2"
              placeholder="Choose a display name"
              onChange={this.handleDisplayNameChange}
            />
          </div>
          <div className="form-group">
            <label>Email</label>
            <input
              type="email"
              className="sign-up__input form-control"
              id="formGroupExampleInput3"
              placeholder="Enter your email address"
              onChange={this.handleEmailChange}
            />
          </div>
          <div className="form-group">
            <label>Password</label>
            <input
              type="password"
              className="sign-up__input form-control"
              id="formGroupExampleInput4"
              placeholder="Password"
              onChange={this.handlePasswordChange}
            />
          </div>
          <div className="form-group">
            <label>Confirm password</label>
            <input
              type="password"
              className="sign-up__input form-control"
              id="formGroupExampleInput4"
              placeholder="Password"
              onChange={this.handleConfirmPasswordChange}
            />
          </div>
          <button type="submit" className="sign-up__button btn btn-
primary btn-lg">Sign Up</button>
        </form>
      </div>
    );
  }
}

export default connect()(SignUp);
2
what is the ~ doing in your import calls? that's not a standard thing, and it will be difficult to reproduce your issue without knowing how to support that. - rossipedia
How do you call createUser method? You use mapDispatchToProps or bindActionCreators? It would be helpful if you can share that part of your code as well. - Tharaka Wijebandara
Can you show the component where you are calling this thunk, and how you are actually calling it? The most likely issue is that you're doing dispatch(createUser), which won't work - it needs to be dispatch(createUser()) (see stackoverflow.com/questions/44334008/… for the same issue from someone else earlier today). - markerikson
Sorry everyone. Updated my code. @markerikson Good call. I did that but now getting an error that event is undefined in the stopDefault function?? - maxwellgover
You did not pass anything to stopDefault in <form onSubmit={this.props.dispatch(this.stopDefault())}> - Anthony Kong

2 Answers

2
votes

You need to use the connect function imported from react-redux to make the createUser function available to the component as a prop, rather than just using the imported function directly. If you don't do this then the function you call is not connected to your redux store, so the returned function (the thunky one) won't be executed.

import React, { Component } from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { createUser } from '~/redux/modules/authentication';
import './SignUp.css';

class SignUp extends Component {
    static propTypes {
        createUser: React.PropTypes.func.isRequired
    }

    stopDefault = (event) => {
        event.preventDefault();
        this.props.createUser(this.state);
    }

    // Rest of component
}

const mapStateToProps = null;
const mapDispatchToProps = {
    createUser
}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(SignUp);
2
votes

You need to use dispatch when you call your redux functions.

By using connect you get dispatch as a prop so you could call this.props.dispatch(createUser(this.state))

Alternatively, connect accepts mapDispatchToProps which like it says, maps dispatch to the props you pass in.

If you did this: connect({}, { createUser }) you would then have createUser available to you to use: this.props.createUser(this.state)