Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

My component doesn't re-render after updating Redux store

I have this menu component where The menu contexts change based on the user input.

For example, If the user clicked RESERVATION button (fig 1) in the menu then to website body will change and the menu context will change to handle reservation features (fig2) <--- (desired behavior), however, the component stop re-render after the component mount.

fig1: | HOME | RESERVATION | ... | etc

fig2: | < | MAKE RESERVATION | ... | etc

What I tried :

It looks like the values in the store are changing and send to the component, too. I tried to use componentWillReceiveProps() but this did not work.

here is an example of my menu component:

import React, { Component } from 'react';
//redux thingy
import {connect} from 'react-redux';

class DefualtMenu extends Component {


  render() {
    return (
      <div className="Defult-Menu-Main-Div">
        <div className="box1">
          <div className="box11" onClick={() => this.props.HandleMenuClick(this.props.MenuBoxes.box11)}>
            <h3 className="boxh3" onClick={() => this.props.HandleMenuClick(this.props.MenuBoxes.box11)}>
              {this.props.MenuBoxes.box11}
            </h3>
          </div>
        </div>
      </div>
    );
  }
}

const mapDispachToProps = (dispach) => {
  return {
    HandleMenuClick: (buttomName) => {
      switch (buttomName){
        case "RESERVATION":{
          dispach({type: "HANDLE_BODY_CHANGE_RESERVATION"})
          break;
        }
      }
    } 
  }
}

const mapStateToProps = (state) => {
  return {
    MenuBoxes: state.MenuBoxes
  }
}

export default connect(mapStateToProps, mapDispachToProps) (DefualtMenu);

Here how I handle the actions:

const reducer = (state = initial_state, action) => {
    const new_state = {...state};

    switch (action.type) {
        }
        case "HANDLE_BODY_CHANGE_RESERVATION": {
            new_state.body = 'reservation';
            if(new_state.userType == 'customer'){
                new_state.MenuBoxes.box11 = '◄'
                new_state.MenuBoxes.box12 = 'DELETE A \n RESERVATION'
                new_state.MenuBoxes.box13 = ''
                new_state.MenuBoxes.box21 = 'MAKE A \n RESERVATION'
                new_state.MenuBoxes.box22 = 'REVIEW \n RESERVATIONS'
                new_state.MenuBoxes.box23 = ''
                new_state.MenuBoxes.box31 = 'UPDATE A \n RESERVATION'
                new_state.MenuBoxes.box32 = ''
                new_state.MenuBoxes.box33 = ''}
            break;
        }
    return new_state;
};

UPDATE

I console.log my states: Here the state when I login to the admin account: the menu component did mount in this stage and everything is alright.

MenuBoxes:
box11: "HOME"
box12: "COUPONS"
box13: ""
box21: "RESERVATION"
box22: "ABOUT US"
box23: ""
box31: "INVENTORY"
box32: "SETTING"
box33: "SIGNOUT"
__proto__: Object
SingInfailureMessege: ""
body: "homepage"
isSignIn: true
showMenu: "default"
userType: "admin"
username: "admin"

When I click on RESERVATION -> The menu component already mount here and the state changed too but the component didn't re-render and change the props

MenuBoxes:
box11: "◄"
box12: "DELETE A ↵ RESERVATION"
box13: ""
box21: "MAKE A ↵ RESERVATION"
box22: "REVIEW ↵ RESERVATIONS"
box23: ""
box31: "UPDATE A ↵ RESERVATION"
box32: ""
box33: ""
__proto__: Object
SingInfailureMessege: ""
body: "reservation"
isSignIn: true
showMenu: "default"
userType: "admin"
username: "admin"
like image 615
Mahmood H. Alnasser Avatar asked Dec 20 '25 21:12

Mahmood H. Alnasser


1 Answers

I disagree, you don't need any of these:

componentWillReceiveProps(nextProps) // maybe not this one
componentDidUpdate(prevProps) // probably this one
shouldComponentUpdate(nextProps, nextState) // possibly this one but not likely

I mean that's the purpose of react and redux, state changes -> checks if props change ->if yes re-renders. The functions above are useful for far more complicated cases then this one.

What is wrong, is the way your reducer is written. Please try going to something simpler in order to test. Please try this switch for starters:

  switch (action.type) {
    case "HANDLE_BODY_CHANGE_RESERVATION":
      return { ...state, MenuBoxes: { box11: "test" } };
      break;
    default:
      return state;
      break;
  }

I am sure it will work. Then start going to more complicated.

Finally i am speculating the mistake is in the way you handle state in the reducer. Never do this:

const new_state = {...state};

By doing this, you directly mutate the state further below (we never do that).

The way you should do it, is create a new object which includes all the changes of the state:

let new_state = {};
...
new_state.body = "reservation";
new_state.MenuBoxes = {};
new_state.MenuBoxes.box12 = "DELETE A \n RESERVATION";

and in the end return the previous state along with the changes like this:

 return { ...state, ...new_state };

I am no expert but i think, right now you mutate state so new state = old state => no re-renders needed

like image 57
Fotis Nalbadis Avatar answered Dec 23 '25 10:12

Fotis Nalbadis



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!