【问题标题】:props is undefined although state has changedprops 未定义,尽管状态已更改
【发布时间】:2020-10-16 15:06:10
【问题描述】:

我是反应新手。我有一个父组件导航栏,其状态为“Total_Item”。该数组是在单击 Modal 时添加的。值正在填充。现在我想获取这个数组的长度并在我的导航组件中显示在我的购物车按钮(目前是一个简单的按钮)上。但它说未定义。

所以数据不会保存在 Navbar 组件的 props (Tot_Item) 中。我确信 react 的呈现方式存在一些概念性错误。在这一点上,一个清晰的解释真的会有所帮助。

请看下面的沙盒:

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

谢谢 萨尔

【问题讨论】:

  • 看起来Navbar 中的任何内容根本不会更新状态,因此传递给Navvthis.state.Total_Item 始终相同。
  • 绘制了 Total_Item 已附加。我记录了它。问题是传递道具
  • 附加到什么?在哪里?在Navbar 中没有任何this.setState({ Total_Item: ... }) 呼叫。 Navbar 只是将this.state.Total_Item 传递给Navvthis.state.Category 传递给Menu。没有任何更新。
  • 我在 Menu 组件中做了 setState (Total_Item=ll7),使用 Listval 函数
  • 好的,在Menu 中有两个对某些this.state.Total_Item 的引用(L35 和 L43),但是对于来自Menu 的那个状态没有做任何事情。您是否尝试更新Navbar 中的状态?在下一行(L45)你console.log(this.props.Tot_Item) 但这不是传递给Menu 的道具,所以我完全希望它是未定义的。 Navv 有一个 Tot_Item。看来您正在将两个组件之间的逻辑混合在一起。

标签: javascript jquery reactjs react-native react-redux


【解决方案1】:

在文件Navbar.jsx 中,this.state.Tot_Item 的值为空数组。使用this.setState函数改变this.state.Tot_Item的值 => 在文件Navv.jsxthis.props.Tot_Item 的值是空数组。更改呈现按钮数组的方式。

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

【讨论】:

    【解决方案2】:

    你不需要在 React 中使用 asyncawait,因为它应该异步工作。 但是,您可以将回调函数传递给 setState 以执行您想要的操作。 该方法应作为 setState 调用中的第二个参数传递,而您传递的函数将不会是运行直到 React 成功更新了状态。

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

    另外,我注意到您在 listval 方法上多次调用 setState。如果您想一次设置多个属性,您实际上不必多次调用setState。由于状态是一个对象,您可以在一次调用中更改您想要的所有属性,如下所示:

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

    至于为什么this.props.Tot_Item在你的Navv组件中总是undefined,原因是子组件不能以任何方式修改其父组件的状态。

    现在您的组件结构如下:Navbar 包含NavvMenuMenu 是包含项目列表的那个,应该更新选定项目的列表,而Navv 只是应该显示所述数组中的项目数。

    但是,有一个问题:您不能将数据直接从 Menu 传递给它的兄弟 Navv 必须有一个父组件(在本例中为 Navbar)从Menu 获取数据并将其传递给Navv。但是,它并没有像你所拥有的那样真正起作用。 子组件 (Menu) 更改父组件 (Navbar) 状态的唯一方法是使用回调方法,如下例所示:

    • Navbar 组件的变化
      // 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>
        );
    
    • Menu 组件的变化
      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 你有一个包含所有这些更改的沙盒示例的工作版本。希望对您有所帮助!

    【讨论】:

    • LonelyPrincess,我欠债了。太感谢了。这对我很有教育意义。正是我正在寻找的那种答案。正如您所强调的,每次子组件尝试更改父状态时,都必须使用回调函数。这是唯一的反应方式吗?我知道您试图纠正我的代码,是否可以更简单/更简单的方式来实现这一点。只是你的额外想法。
    • 很高兴这对您有用! :) 至于您的问题,我相信这是您刚开始时最简单的方法。对于具有少量组件的小型应用程序,回调应该易于管理并帮助您了解数据在组件之间的真实流动方式,这有助于您开始 React 世界。
    • 当然,对于具有大量组件的大型项目,使用回调方法很容易失控并使您的应用程序难以维护,在这些情况下,首选其他替代方案。
    • 另一种方法是使用 Redux 等库来实现可以在所有组件之间共享的全局状态,但我不建议在您的情况下使用它,因为它可能很难理解第一的。熟悉 React 的基础知识后,有兴趣的可以看看。 ;) redux.js.org/basics/usage-with-react
    • 如果你不想依赖外部库,最近版本的 React 还提供了一个 Context API 可以用来实现同样的事情,所以如果你也可以随时查看有时间。 reactjs.org/docs/context.html
    【解决方案3】:

    您可以进行以下更改。

    1. 你可以把你的状态放在构造函数中。

    2. 您需要使用 FAT 运算符和您喜欢的 setState 声明 ListVal。 (在我的情况下,我在模态弹出窗口中单击“确定”按钮并将其显式设置为 2,并且它也出现在屏幕上)

        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;
      

    【讨论】:

    • 感谢 Raghvender。我试着按照你说的做,但它似乎对我不起作用,我尝试使用 fat 函数,但它给出了错误。
    • 感谢 Raghvender。Total_item 源自 ll7。问题是异步在导航栏组件中不起作用。尽管您解决了问题,但这导致了我的代码中的另一个问题。如何使异步功能工作。请看沙盒:codesandbox.io/s/angry-leaf-n5njb
    • 为什么在执行 this.setState 时使用 await ?
    • Raghvender 我是新手。我只想在控制台上看到结果
    • 不,伙计,这绝对不是 react 的工作方式。您可以先了解 react 中的状态,然后继续
    猜你喜欢
    • 2019-08-31
    • 2018-08-04
    • 1970-01-01
    • 1970-01-01
    • 2012-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-06
    相关资源
    最近更新 更多