简体   繁体   中英

React component doesn't update after Redux store change

These are my classes and component:

App.js:

import { connect } from "react-redux";
import Main from "./components/main/Main";
import * as actions from "./redux/actions";
import { bindActionCreators } from "redux";
import { withRouter } from "react-router";

function mapStateToProps(state) {
  console.log(state);

  return {
    // naming must be exact same as function in reducer
    auth: state.auth,
    errorBag: state.errorBag
  };
}
function mapDispatchProps(dispatch) {
  return bindActionCreators(actions, dispatch);
}
const App = withRouter(connect(mapStateToProps, mapDispatchProps)(Main));
export default App;

Main.js:

import React, { Component } from "react";
import { Redirect } from "react-router";
import { Route } from "react-router-dom";
import Login from "./../login/Login";
import Home from "./../home/Home";

class Main extends Component {

  render() {

    return (
      <div>
        <Route
          path="/login"
          render={param => {
            return <Login {...this.props} {...param} />;
          }}
        />

        {!this.auth ? <Redirect to="/login" /> : <Home />}
      </div>
    );
  }
}

export default Main;

reducer.js:

import { combineReducers } from "redux";

function authenticateReducer(state = null, action) {
  switch (action.type) {
    case "AUTHENTICATE": {
      return action.token;
    }
    default: {
      return state;
    }
  }
}
function errorBagReducer(state = [], action) {
  switch (action.type) {
    case "ADD_ERROR": {


      console.log("called");

      return { [action.area]: action.error };
    }
    default:
      return state;
  }
}

const rootReducer = combineReducers({ authenticateReducer, errorBagReducer });
export default rootReducer;

actions.js:

import axios from "axios";

export function startSignUp(signUpData) {
  return dispatch => {

    return axios
      .post("http://localhost:8000/api/v1/user/sign-up/", signUpData)
      .then(res => {
        console.log(res);
        authenticate(res.data.shaba);
      })
      .catch(error => {
        console.log(error.data);
      });
  };
}
export function addErrorIntoBag(area, error) {
  return {
    type: "ADD_ERROR",
    area,
    error
  };
}


function authenticate(token) {
  return {
    type: "AUTHENTICATE",
    token
  };
}

Login.js:

import React, { Component } from "react";
import "./login.css";
import InlineAlert from "./../alerts/InlineAlert";

class Login extends Component {
  constructor(props) {
    super(props);
  }
  getAreaName = () => "LOGIN";
  submitHandler = event => {
    event.preventDefault();
    const email = event.target.elements.email.value;
    const code = event.target.elements.code.value;
    const password = event.target.elements.password.value;
    if (password === "" || code === "" || email === "") {
      this.props.addErrorIntoBag(this.getAreaName(), "fill the form please");

      return;
    }
    const data = {
      email: email,
      password: password,
      national_code: code
    };
    this.props.startSignUp(data);
    this.forceUpdate();
  };
  render() {
    return (
      <div id="parent" onSubmit={this.submitHandler}>
        <form id="form_login">
          <h2>Login</h2>
          <br />
          <div className="form-group">
            <label forhtml="exampleInputEmail1">National code</label>
            <input
              key="code"
              type="text"
              className="form-control"
              id="exampleInputEmail1"
              aria-describedby="emailHelp"
              name="code"
            ></input>
          </div>
          <div className="form-group">
            <label forhtml="exampleInputPassword1">Email</label>
            <input
              type="email"
              className="form-control"
              id="email"
              name="email"
              key="email"
            ></input>
          </div>
          <div className="form-group">
            <label forhtml="exampleInputPassword1">Password</label>
            <input
              type="password"
              className="form-control"
              id="name"
              name="password"
              key="password"
            ></input>
          </div>
          <div className="form-group form-check"></div>
          <button type="submit" className="btn btn-light">
            SIGN-UP
          </button>
        </form>
        {/* drill down checking 🤯  */}
        {this.props.errorBag && this.props.errorBag[this.getAreaName()] && (
          <InlineAlert error={this.props.errorBag[this.getAreaName()]} />
        )}
      </div>
    );
  }
}

export default Login;

When I call submitHandler in Login.js and form is empty it calls an action to changes the redux store and Login.js component must update and InlieAlert component must appear in the screen, but anything doesn't change!

Is it because of my Main.js that is middle of Login and Redux?

I'm confused!

I guess you forgot to call dispatch in startSignUp function. It is not enough just to return from authenticate the object as you did with { type: "AUTHENTICATE", token } but you need to pass to dispatch also. In this way you are triggering a state change.

From the documentation of dispatch(action) :

Dispatches an action. This is the only way to trigger a state change.

Maybe you could try to do somehow the following:

export function startSignUp(signUpData) {
  return dispatch => {
    return axios
      .post("http://localhost:8000/api/v1/user/sign-up/", signUpData)
      .then(res => {
        console.log(res);
        // missing dispatch added
        dispatch(authenticate(res.data.shaba));
      })
      .catch(error => {
        console.log(error.data);
      });
  };
}

So you can think of like calling as the following at the end for the state change:

dispatch({
  type: "AUTHENTICATE",
  token
});

I hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM