javascriptreactjsreduxredux-thunkdispatch

dispatch does not work in React Redux for authentication


I call register, the function is executed, but it's internal dispatch function is not executed,.

Register

import React, { Component } from "react";
import { Link, Navigate } from 'react-router-dom'; 
import { connect } from 'react-redux';
import { register } from '../actions/auth'

class Register extends Component {
  constructor(props) {
    super(props);
    this.state = {
      username: '',
      password: '',
      re_password: '',
      accountCreated: false
    }
  }

  onSubmit(e) {
    e.preventDefault();

    let { username, password, re_password } = this.state
    if (password === re_password) {
      register(username, password, re_password); <-- here

      this.setState({ accountCreated: true });
    }
  }

  render() {
    if (this.state.accountCreated) {
      return <Navigate to='/' />
    }

    return (
      <div className="container mt-5">
        <h1>Register for an Account</h1>
        <p>Create an account with our Session Auth application</p>
        <form onSubmit={(e) => this.onSubmit(e)}>
          <div className="form-group">
            <label htmlFor="username" className="form-label">
              Username: 
            </label>
            <input
              type="text"
              className="form-control"
              placeholder="Username*"
              name='username'
              value={this.state.username}
              onChange={(e) => this.setState({ username: e.target.value })} 
              required
            />
          </div>
          <div className="form-group">
            <label htmlFor="password" className="form-label">
              Password:
            </label>
            <input
              type="password"
              className="form-control"
              placeholder="Password*"
              name='password'
              value={this.state.password}
              onChange={(e) => this.setState({ password: e.target.value })} 
              minLength={6}
              required
            />          
          </div>
          <div className="form-group">
            <label htmlFor="confirm_password" className="form-label">
              Confirm Passeord:
            </label>
            <input
              type="password"
              className="form-control"
              placeholder="Confirm Password*"
              name='re_password'
              value={this.state.re_password}
              onChange={(e) => this.setState({ re_password: e.target.value })} 
              minLength={6}
              required
            />
          </div>
          <button className="btn btn-primary mt-3" type="submit">Register</button>
        </form>
        <p className="mt-3">
          Already have an Account? <Link to='/login'>Sign In</Link>
        </p>
      </div>
    )
  }
}

export default connect(null, { register })(Register); <-- here

file actions/auth

import axios from 'axios';
import {
  REGISTER_SUCCESS,
  REGISTER_FAIL
} from './types';
import Cookies from 'js-cookie';

const URL = `${process.env.REACT_APP_API_URL}`;

export const register = (username, password, re_password) => async dispatch => {
  const csrftoken = Cookies.get('csrftoken');
  const config = {
    headers: {
      'Accept': 'application/json',
      'Content-Type' : 'application/json',
      // 'Cache-Control' : 'no-cache'
      'X-CSRFToken' : csrftoken
    }
  };

  const body = JSON.stringify({ username, password, re_password });

  try { 
    const res = await axios
      .post(URL + '/accounts/register', body, config)
      .catch((err) => console.log(err));
        
    if (res.data.error) {
      dispatch({
        type : REGISTER_FAIL
      });
    } else {
      dispatch({
        type : REGISTER_SUCCESS
      });
    }
  } catch (err) {
    dispatch({
      type : REGISTER_FAIL
    });
  }
};

file reducers/auth

import {
  REGISTER_SUCCESS,
  REGISTER_FAIL
} from '../actions/types';

const initilState = {
  isAthenticated: null,
  username: '',
  first_name: '',
  last_name: '',
  phone: '',
  city: ''
};

export default function(state = initilState, action) {
  const { type, payload } = action;

  switch(type) {
    case REGISTER_SUCCESS:
      return {
        ...state,
        isAthenticated: false
      }

    case REGISTER_FAIL:
      return state

    default:
      return state
  }
};

dispatch must be executed, information will be sent to the server and the type will be determined.


Solution

  • The connect Higher Order Component injects selected state and dispatchable actions as props into the component it is decorating. In your code you are calling the register action creator directly and not the version that was wrapped in a call to dispatch and injected as a prop.

    import React, { Component } from "react";
    import { Link, Navigate } from 'react-router-dom'; 
    import { connect } from 'react-redux';
    import { register } from '../actions/auth'; // <-- register #1
    
    class Register extends Component {
      ...
    
      onSubmit(e) {
        e.preventDefault();
    
        const { username, password, re_password } = this.state;
        if (password === re_password) {
          register(username, password, re_password); // <-- calling register #1
    
          this.setState({ accountCreated: true });
        }
      }
    
      ...
    }
    
    export default connect(null, { register })(Register); // <-- register #2
    

    You should be calling the register that is injected as props into the Register component.

    import React, { Component } from "react";
    import { Link, Navigate } from 'react-router-dom'; 
    import { connect } from 'react-redux';
    import { register } from '../actions/auth'; // <-- register #1
    
    class Register extends Component {
      ...
    
      onSubmit(e) {
        e.preventDefault();
    
        const { username, password, re_password } = this.state;
        if (password === re_password) {
          this.props.register(username, password, re_password); // <-- calling register #2
    
          this.setState({ accountCreated: true });
        }
      }
    
      ...
    }
    
    export default connect(null, { register })(Register); // <-- register #2