sal abb
sal abb

Reputation: 121

props is undefined although state has changed

I am new in react. I have a parent component Navbar, that has state "Total_Item". This array is added on click of Modal. The values are populating. Now i want to get the length of this array and show on my cart button(presently a simple button), in my Navv component. But it says undefined.

So the data is not saved in props (Tot_Item ) in the Navbar component. I am sure there is some conceptual error how react renders. A clear explanation will really help at this point.

Please see the sandbox below:

https://codesandbox.io/s/blazing-sky-cet22

Thanks sal

Upvotes: 0

Views: 808

Answers (3)

zZHaOZz
zZHaOZz

Reputation: 11

In file Navbar.jsx, value of this.state.Tot_Item is empty array. Use this.setState function to change the value of this.state.Tot_Item => In file Navv.jsx value of this.props.Tot_Item is empty array. Change the way to render an array of button.

https://codesandbox.io/s/stoic-rubin-wg2fo

Upvotes: 1

LonelyPrincess
LonelyPrincess

Reputation: 461

You don't need to use async and await in React, as it's supposed to work asynchronously. You can, however, pass a callback function to setState to do what you want. That method shall be passed as a second parameter in your setState call, and the function you pass will not be run until React has successfully updated the state.

this.setState({
  myVar: 'value to print'
}, () => console.log(this.state.myVar));

Also, I've noticed you're calling setState a lot of times on your listval method. You actually don't have to call setState multiple times if you want to set many properties at once. Since the state is an object, you can change all of the properties you want in a single call, like this:

this.setState({
  Select_Price: ll,
  Select_Item: ll3,
  Select_Item_TotalPrice: ll6,
  Total_Item: ll7
});

As for why this.props.Tot_Item is always undefined in your Navv component, the reason is that a children component cannot modify its parent' state in any way.

Right now your components are structured in the following way: Navbar contains both Navv and Menu. Menu is the one that contains a list of items and is supposed to update the list of selected items, while Navv is just supposed to display the number of items in said array.

However, there's a problem: you cannot pass data directly from Menu to its sibling, Navv. It's necessary to have a parent component (in this case, Navbar) that gets the data from Menu and pass it down to Navv. However, it doesn't really work as you have it. The only way a children component (Menu) can alter the parent' (Navbar) state is by using a callback method, as seen in the example below:

  • Changes in Navbar component
  // CHANGE: Create callback function to send data to parent
  updateTotalItems = total => {
    this.setState({ Total_Item: total }, () =>
      console.log("total items in navbar", this.state.Total_Item)
    );
  };

  // CHANGE: pass callback method as props to the children component that modifies the item counter
  render() {
    return (
      <React.Fragment>
        <Navv Tot_Item={this.state.Total_Item} />
        <Menu
          updateTotalItems={this.updateTotalItems}
          Objs_Type={this.state.Category}
        />
      </React.Fragment>
    );
  • Changes in Menu component
  Listval() {
    /* ... */

    // CHANGE: No need to call setState multiple times
    this.setState(
      {
        Select_Price: ll,
        Select_Item: ll3,
        Select_Item_TotalPrice: ll6,
        Total_Item: ll7
      },
      () => {
        // CHANGE: Use callback function to send the array length to the parent component
        this.props.updateTotalItems(this.state.Total_Item.length);
      }
    );
  }

Here you have a working version of your sandbox example with all of these changes. Hope it helps!

Upvotes: 0

Raghvender Kataria
Raghvender Kataria

Reputation: 1485

You can do the below changes.

  1. You can place your state in constructor.

  2. You need to declare ListVal using FAT operator and setState of what you like. (In my case I have explicitly set it to 2 on click of OK button in Modal popup and its appearing on the screen too)

      import React, { Component } from "react";
     import Menu from "./Menu";
     import Navv from "./Navv";
    
     class Navbar extends Component {
    
       constructor(props)
       {
         super(props);
         this.state = {
           Category: [
             {
               id: 1,
               FoodType: "Chinese",
               Menu: ["Egg Drop", "Chicken Fried", "Beef Fried"],
               Price: [2, 8, 10]
             },
    
    
         {
           id: 2,
           FoodType: "Mexican",
           Menu: ["Veg Burrito", "Chicken Burrito", "Beef Burrito"],
           Price: [7, 8, 10]
         }
       ],
    
       One_Item: [
         {
           listvalue: null,
           Select_Item: null,
           Select_Price: null,
           Select_Quantity: null,
           Select_Item_TotalPrice: null
         }
       ],
    
       Total_Item: 0
     };
     }
    
    
     Listval=async()=>{
     this.setState({ Total_Item: 2});
     }
    
     render() {
     return (
       <React.Fragment>
         <Navv Tot_Item={this.state.Total_Item} />
         <Menu
            Listvalll={this.Listval}
           Objs_Type={this.state.Category}
         />
       </React.Fragment>
     );
     }
     }
     export default Navbar;
    

Upvotes: 0

Related Questions