reactjs React js:无法将数组中的第一个对象作为属性发送

fnx2tebb  于 2023-02-15  发布在  React
关注(0)|答案(2)|浏览(154)

我试图构建一个小型React.js应用程序,我的组件结构如下所示:

MainComponent
    - CategoryList
        -Category
    - ItemsList 
        -Item

我的MainContent组件在componentDidRender:中对其状态数据执行ajax请求,该请求返回以下对象:

data:[
Object[0]
 -name
 -items[]
,
Object[1],
Object[2]
]

现在,我想让我的CategoryList按名称写出所有的Categories,这很好,但我还想打印出所选类别的项目。

var ItemsList = React.createClass({
    render:function(){

         var itemNodes = this.props.category.items.map(function(item){
            return (
                <Item name={item.name} />
            );
        });

        return(
            <div className="itemList">
            {itemNodes}
            </div>
        );
    }
});

这就是我从父组件传递"category"属性的方法

<ItemsList category={this.state.data[0]} />

我收到一个错误,说"无法读取未定义的属性项",这意味着类别prop从未被分配。我知道www.example.com包含一个对象数组,所以我在这里没有看到这个错误。this.state.data contains an array of objects so I don´t see the error here.
我做错了什么?
编辑:根据请求,这是我的主要组件:

var MainComponent = React.createClass({
    getInitialState:function(){
        return {data: []};
    },
    componentDidMount:function(){
        $.ajax({
            type:'get',
            url: '/categories',
            dataType: 'json',
            success:function(data){
                this.setState({data: data});
            }.bind(this)

        });
    },
    render: function(){
        return (
        <div className="row">
            <div className="col-md-6">
                <CategoryList categories={this.state.data} />
            </div>
            <div className="col-md-6">
            <ItemsList category={this.state.data[0]} />
            </div>
        </div>

        );
    }
});
vojdkbi0

vojdkbi01#

Modern(2023)React告诉你要使用函数组件,所以,如果你想从服务器上传数据并在组件中呈现它,你需要使用所谓的“钩子”,名为“useEffect”和“useState”。
因此,首先导入它们:

import React, { useEffect } from "react";
import { useState } from "react";

接下来,创建一个功能组件并初始化组件中的'state'和'set_state function':

export default function FuctionName() {
   let [ value, set_value ] = useState([]) 
}

这将创建“value”变量,该变量将在渲染过程中保持其状态。
然后,您发出一个获取请求(在组件的return语句之前)(但您需要将其放在useEffect函数中以获得一致的行为):

useEffect(() => {
    fetch('url')
    .then(response => response.json())
    .then(server_data => {
        set_value(server_data);
        })}
, [])

现在,你明白为什么我们需要状态了:因为我们需要将从服务器返回的数据存储在一个变量中,并且我们需要这些数据在渲染中保留。另外,您认为现在可以在组件的返回渲染中使用数据,如下所示:

return (
    <h1>the data from server: {value.name_of_key}</h1>
)

但是你会遇到“阅读未定义”的错误。
首先,检查服务器返回的对象类型是否正确,在fetch请求中放入console.log语句:

useEffect(() => {
    fetch('url')
    .then(response => response.json())
    .then(server_data => {
        set_value(server_data);
        console.log(server_data);
        })}
, [])

它应该是一个包含对象的列表,例如:[{}、{}、{}]。
如果是,那么问题是组件在从服务器接收数据之前呈现。组件将首先呈现,然后从服务器接收数据。如果在render语句中调用state变量,它将调用空状态。
因此,为了缓解这种情况,您的代码应该准备好呈现空状态和带有数据的状态。最简单的方法是条件呈现。仅当有数据要呈现时,才呈现带有数据的组件:

return (
    {value && <h1>the data from server: {value.name_of_key}</h1>}
)

'value &&'部分允许您实现以下逻辑:

  • 如果值(来自服务器的数据)为空,则不呈现任何内容(因此不调用任何来自数据的键)
  • 如果该值不为空,则呈现调用数据的组件

为什么会这样呢?“&&”的表达方式(a和B)从右向左求值。如果第一个变量求值为“false”,则它不再继续并停止在此。变量“value”的初始状态是空对象('let [ value,set_value ] = useState([])' -还记得吗?).因此,当服务器在第一次呈现时还没有返回数据时,表达式“value &&”的计算结果为“false”并且不呈现表达式的右侧部分。当服务器返回数据时,它使用数据调用“setState”函数,并强制第二次呈现组件。第二次表达式“value &&”的计算结果为“true”React会转到表达式的右边部分,实际上呈现了包含数据的组件。您可以通过将console.log语句放在fetch请求和return语句中来检查此过程,您将看到函数解析的顺序。
希望能有所帮助。另外,请查看这篇文章:https://daveceddia.com/react-before-render/
快乐编码〉〉

x4shl7ld

x4shl7ld2#

主组件在data中用一个空数组初始化状态,因为没有this.state.data[0],所以渲染总是失败。
人们可能会回答说 AJAX 请求将提供这个状态属性data的值(假设你的web服务提供了一个有效的数组)。然而,这只发生在从服务器接收到响应之后,而在第一次呈现之后不会发生。
如果信息立即可用,则可以在方法componentWillMount或组件构造函数上使用setState,以避免触发第二次渲染:
componentWillMount()在装载发生前立即调用。它在render()之前调用,因此在此方法中同步设置状态不会触发重新呈现。避免在此方法中引入任何副作用或订阅。
在这种情况下,由于我们正在等待远程信息,React文档仍然建议使用componentDidMount,这里也使用了componentDidMount
在装入组件后立即调用componentDidMount()。需要DOM节点的初始化应在此处进行。如果需要从远程终结点加载数据,则这是示例化网络请求的好位置。在此方法中设置状态将触发重新呈现。
因此,组件的render方法必须能够处理丢失的状态变量。有多种方法可以解决这个问题,但是在我们得到data之前阻止嵌套元素被呈现是最简单的方法。通过一些额外的逻辑,应用程序可以通知用户特定的组件正在加载。

render() {
    return (
    <div className="row">
        <div className="col-md-6">
            <CategoryList categories={this.state.data} />
        </div>
        <div className="col-md-6">
          {this.state.data.length > 0 &&
            <ItemsList category={this.state.data[0]} />
          }
        </div>
    </div>
    );
}

相关问题