使用异步值设置状态

时间:2018-09-15 17:06:49

标签: reactjs

我正在尝试获取React组件的数据并将其设置为处于状态的嵌套对象:

import React from 'react';
import './App.css';
import XLSX from "xlsx";

class App extends React.Component {
  constructor(props){
    super(props);
    this.state = {
      isLoading:false,
      cards:{}
    }
  }

  componentDidMount(){
    this.setState({isLoading:true});

    /* convert xlsx to JSON */
    fetch("../data/Cards_v0.1.xlsx")
    .then((d)=> d.arrayBuffer()).then((d)=>{

      const data = new Uint8Array(d);
      const workbook = XLSX.read(data, {type:"buffer"});
      const sheet = workbook.Sheets["Deck"];
      const cardsJSON = XLSX.utils.sheet_to_json(sheet,{range:1});

      let cards = {};
      for(let i=0; i<cardsJSON.length; i++){
        for(let j=0; j<cardsJSON.length; j++){
          cards[cardsJSON[i].Name] = cardsJSON[i];
        }
      }
      this.setState({cards:cards, isLoading:false});
  });
  }

  render() {
    if(this.state.isLoading){
      return <div>Loading</div>;
    }
    return (
      <div>
        { this.state.cards.Single.Name }
      </div>
    );
  }
}

export default App;

React devtools显示对象处于状态,其中 cards> Single> Name 为“ Single”,但是{this.state.cards.Single.Name}抛出 TypeError:无法读取属性'Name'未定义。

最让我感到困惑的是,{this.state.cards.Single}抛出了对象作为React子对象无效(找到:键为{Name,Type,Rarity,Text,Money}的对象)。如果要渲染子级集合,请改用数组。

因此,Name键没有被调用时被找到,但是当我调用它时,该对象变成了未定义状态?

非常困惑。任何帮助表示赞赏!

1 个答案:

答案 0 :(得分:1)

反应不知道如何显示对象,因此,{this.state.cards.Single}将抛出Objects are not valid as a React child

设置React状态还有一些奇怪的选择。由于该组件始终会在装载时获取数据,因此将isLoading缺省设置为true,然后在成功获取响应时将其设置为false更为有意义。

我不知道您的cardsJSON的结构,但是下面的示例显示了两种显示嵌套JSON的方式。

  • 将其包装在pre代码HTML元素中并使用JSON.stringify(obj, replacer, spaces)
  • this.state.cards破坏对象属性(如果这些属性中的任何一个也是嵌套对象,那么它们也需要被破坏!),然后在表,列表中显示所有被破坏的数据等

工作示例:https://codesandbox.io/s/km3wwvqqzv

Example.js

import React, { Component, Fragment } from "react";
import DisplayCode from "./displayCode";
import DisplayList from "./displayList";

export default class Example extends Component {
  state = {
    isLoading: true,
    cards: {}
  };

  componentDidMount = () => {
    fetch("https://jsonplaceholder.typicode.com/users")
      .then(response => response.json())
      .then(json => this.setState({ cards: json, isLoading: false }));
  };

  render = () =>
    this.state.isLoading ? (
      <div>Loading</div>
    ) : (
      <Fragment>
        <DisplayCode cards={this.state.cards} />
        <DisplayList cards={this.state.cards} />
      </Fragment>
    );
}

displayCode.js

import React, { Fragment } from "react";

export default ({ cards }) => (
  <Fragment>
    <h3>Display JSON as code:</h3>
    <pre style={{ height: 300, overflowY: "auto" }}>
      <code>{JSON.stringify(cards, null, 4)}</code>
    </pre>
  </Fragment>
);

displayList.js

import map from "lodash/map";
import React, { Fragment } from "react";

export default ({ cards }) => (
  <Fragment>
    <h3 style={{ marginTop: 30 }}>Display JSON as list:</h3>
    <ul style={{ height: 300, overflowY: "auto" }}>
      {map(
        cards,
        ({
          id,
          name,
          username,
          email,
          address: {
            street,
            suite,
            city,
            zipcode,
            geo: { lat, lng }
          }
        }) => (
          <li key={id}>
            <strong>id:</strong> {id}
            <ul>
              <li>
                <strong>Username:</strong> {username}
              </li>
              <li>
                <strong>Name:</strong> {name}
              </li>
              <li>
                <strong>Email:</strong> {email}
              </li>
              <li>
                <strong>Street: </strong>
                {street}
              </li>
              <li>
                <strong>Suite: </strong>
                {suite}
              </li>
              <li>
                <strong>City: </strong>
                {city}
              </li>
              <li>
                <strong>Zipcode: </strong>
                {zipcode}
              </li>
              <li>
                <strong>Lat: </strong>
                {lat}
              </li>
              <li>
                <strong>Lng: </strong>
                {lng}
              </li>
            </ul>
          </li>
        )
      )}
    </ul>
  </Fragment>
);