将从本地Restify服务器获取的对象添加到状态为

时间:2019-02-18 13:38:20

标签: reactjs fetch

因此,我正在上一门网络编程课程,在其中我们得到了这项任务,以设计一些简单的前端来订购色拉,获取所有组件等。它先前存储在.js文件中,追随时尚

let inventory = {
    Sallad: {price: 10, foundation: true, vegan: true},
    Pasta: {price: 10, foundation: true, gluten: true},
    'Salad + Pasta': {price: 10, foundation: true, gluten: true},
    'Salad + Matvete': {price: 10, foundation: true, vegan: true, gluten: true},

    'Kycklingfilé': {price: 10, protein: true},
    'Rökt kalkonfilé': {price: 10, protein: true},

    'Böngroddar': {price: 5, extra: true, vegan: true},
    'Chèvreost': {price: 15, extra: true, lactose: true},

    Honungsdijon: {price: 5, dressing: true, vegan: true},
    Kimchimayo: {price: 5, dressing: true},

    .
    .
    .

};

export default inventory;

然后将其导入到我的App.js中,该App在创建react项目时创建,并作为prop发送给另一个组件,该组件负责沙拉的组成,最终将其发送回以as的形式发送道具。

所以我们现在要做的是改为从本地rest(?)服务器获取此清单。所以如果我去

http://localhost:8080/proteins

它将打开一个页面,该页面仅显示包含所有不同蛋白质选择的数组

["Kycklingfilé","Rökt kalkonfilé","Norsk fjordlax","Handskalade räkor från Smögen","Pulled beef från Sverige","Marinerad bönmix"]

然后转到

http://localhost:8080/proteins/Kycklingfilé

将为您提供另一页包含该成分属性的页面

{"price":10,"protein":true}

我试图用所有成分作为状态内部的属性重新创建库存对象是

class App extends Component {

constructor(props) {
    super(props);
    this.state = {
        salads: [],

        inventory: {

        }
    };
}

componentDidMount() {
    const base = "http://localhost:8080/";
    const pURL =  base + "proteins/";
    const fURL =  base + "foundations/";
    const eURL =  base + "extras/";
    const dURL =  base + "dressings/";

    fetch(fURL).then(response => response.json()).then(data => {
        data.forEach(e => {
            fetch(fURL + e).then(response => response.json()).then(data => {
                Object.assign(this.state.inventory, {e : data})
            })
        })
    });

    fetch(pURL).then(response => response.json()).then(data => this.setState({data}));
    fetch(eURL).then(response => response.json()).then(data => this.setState({data}));
    fetch(dURL).then(response => response.json()).then(data => this.setState({data}));
}

我一直在使用

{JSON.stringify(this.state)}

尝试查看发生了什么,并使用此代码将其显示为

{"salads":[],"inventory":{},"data":["Ceasardressing","Dillmayo","Honungsdijon","Kimchimayo","Pesto","Rhodeisland","Rostad aioli","Soyavinägrett","Örtvinägrett"]}

因此,这种提取对于获取某种类型的所有成分都可以正常工作,我想这只是敷料,因为它每次都会对最后三个提取进行数据覆盖。但是问题在于库存完全是空的。

如果我改为这样写

fetch(fURL).then(response => response.json()).then(data => {
        data.forEach(e => {
            Object.assign(this.state.inventory, {e: fetch(fURL + e).then(response => response.json().then())})
        })
    });

输出变为

{"salads":[],"inventory":{"e":{}},"data":["Ceasardressing","Dillmayo","Honungsdijon","Kimchimayo","Pesto","Rhodeisland","Rostad aioli","Soyavinägrett","Örtvinägrett"]}

因此它添加了'e'对象,这是另一个问题,因为我希望它是当前元素的值,但是它完全为空,并且我不知道如何在编写时从那几秒钟获取数据这样。因此,这就是为什么它现在看起来像第一个代码段中那样,甚至在清单中都没有空的“ e”。

最后,如果我像第二个例子那样写,只是e:e像这样

fetch(fURL).then(response => response.json()).then(data => {
        data.forEach(e => {
            Object.assign(this.state.inventory, {e: e})
        })
    });

输出变为

{"salads":[],"inventory":{"e":"Salad + Quinoa"},"data":["Ceasardressing","Dillmayo","Honungsdijon","Kimchimayo","Pesto","Rhodeisland","Rostad aioli","Soyavinägrett","Örtvinägrett"]}

因此,直到代表特定类型成分的字符串数组中的.forEach似乎一切都在工作,因为它设法使用数组元素之一的值将其放入清单中的'e'。虽然它只是列表中的最后一个,但是我想这是由于这样的问题,它只是使对象为“ e”而不是当前元素的值,并覆盖每个项目。

很抱歉,如果所有杂乱无章的问题都不清楚,但是我要实现的目标是库存{}处于内部状态,看起来就像在单独文件中时的状态一样,以便在创建组件时可以发送this.state.inventory而不是导入的清单作为prop。并使用我们可以从不同页面获取的内容进行创建。

2 个答案:

答案 0 :(得分:0)

撰写时

{e : data}

您只需创建一个新对象即可。这会将键“ e”的值设置为变量“ data”的当前值。不涉及名为“ e”的变量:

const e = 'hello';
console.log(e); // "hello"
console.log({ asd: e }); // { asd: "hello" }
console.log({ e: "asd" }); // { e: "asd" }
console.log({ e: asd }); // ReferenceError: asd is not defined

您要尝试使用的是变量e的值作为要设置的键。在javascript中,可以使用[]来完成,就像这样:

const e = 'hello';
console.log({ [e]: "world" }); // { hello: "world" }

// this is necessery whenever you want a key that is not a simple word
console.log({ ["key with spaces"]: "world" }); // { "key with spaces": "world" }
console.log({ [e + e]: "world" }); // { hellohello: "world" }

编辑: 上面的代码还有另一个问题,您迟早可能会遇到:

在React中,您应该从不直接修改this.state。务必经历this.setState()

https://reactjs.org/docs/state-and-lifecycle.html#using-state-correctly

在您的情况下,这有点困难,因为您要发出多个请求,每个请求都会影响您状态(inventory)中的同一键。 因为您不知道请求以什么顺序到达,以及每次新数据到达时React是否实际上会setState还是同时全部完成,所以您不能简单地使用this.setState({ inventory: newInventory })。相反,您应该使用here中所述的函数版本。不幸的是,这在一开始可能很难理解:(

在您的情况下,我会这样解决:

fetch(fURL).then(response => response.json()).then(data => {
    data.forEach(e => {
        fetch(fURL + e)
          .then(response => response.json())
          .then(data => this.setState((prevState) => ({
            inventory: Object.assign({}, prevState.inventory, {[e]: data}),
          })));
          })
    })
});

这里需要注意的几件事:

  1. 请注意({中的(prevState) => ({ ... }):这是arrow function that returns an object
  2. 我们正在将功能传递给this.setState(有关详细信息,请参见上面的链接)。此函数接收当前状态作为参数(prevState),并应返回新状态。 (尽管它可以省略保持不变的旧状态键)。这比直接将新状态传递给this.setState更好,因为当同时发生多个setState时,React可以按正确的顺序应用传递的函数,以使所有更改都发生,但是如果传递对象,必须决定选择其中一个对象来“赢”,以免更改丢失。
  3. Object.assign({}, prevState.inventory, {[e]: data})中,我们无需修改prevState.inventory,而是创建一个包含更新的广告资源的新对象。即使在this.setState中,也永远不要修改旧状态。

希望这会有所帮助:)

答案 1 :(得分:0)

因此,根据@sol的建议,使用[e]为每种成分创建对象,此代码

*************
*First Title*
*************

Lots and lots and lots of text
that fill this section up
to tell you things about something          


**************
*Second Title*
**************

Some Text goes here


*************
*Third Title*
*************

Lots of text goes here
with CRs etc
     and tabs

现在有效。我认为为什么对我的“故障排除”而言,仅在render中打印整个状态的JSON.stringify看起来并不成功,原因是在保存代码后刷新响应时,渲染不正确。更新页面会使页面全部空白,但是通过链接单击另一个页面然后返回即可修复该页面。不知道为什么,但我会接受。