简体   繁体   English

为什么在React中状态更改后组件不重新渲染

[英]Why aren't the components re-rendering after a state change in React

I am trying to get data from the Coin Market Cap API and display the information in some very basic cards. 我正在尝试从Coin Market Cap API获取数据,并在一些非常基本的卡中显示信息。 I have tried many things and have comments showing what I have tested. 我尝试了很多事情,并有评论显示了我所测试的内容。 Please help. 请帮忙。

This is the Parent: 这是父母:

import React, { Component } from 'react';
import './App.css';
import CardList from './CardList';
// a test file for starting off.
// import { coinObj } from './coinObj';


class App extends Component {
  //I have tried with props here too, but don't know why that would matter in the case.
  constructor(props) {
    super(props)
    this.state = {
      coinObj: [],
    }
  }

  //Get information from coinmarketcap api.
  componentDidMount() {
    fetch('https://api.coinmarketcap.com/v2/ticker/')
      .then(response => response.json())
      .then(parsedJSON => this.setState(
        {coinObj: parsedJSON.data}
      ))
      .catch(error => console.log('Something went wrong!', error))

      // .then(coinObj => console.log(coinObj))
  }
  //render cards with data from api
  //The state is changed when I run this with the React Dev tools but it does not render new info.
  render() {
    let { coinObj } = this.state;
    //This console loads twice as expected and the second time it has the object from coinmarketplace.
    console.log(coinObj);

    return !coinObj.length ?
      <h2>Loading</h2> :    
    (
      <div>
        <h1>Coins and Stocks</h1>
        <CardList coinObj={ coinObj } />
      </div>
    );

    //I use this below to try and force the program forward but then I cannot read any values from the object I put in state.
    /*return (
      <div>
        <h1>Coins and Stocks</h1>
        <CardList coinObj={ coinObj } />
      </div>
    );
    */  
  }
}

export default App;

This is one Child: 这是一个孩子:

import React from 'react';
import Card from './Card';

const CardList = ({coinObj}) => {
    //This array holds the id of the coins I am interested in.
    const coinsIdArray = [1, 1027, 1958, 2577];
    //This shows me the first object in my object of objects when the cards are commented bottom is out.
    console.log(coinObj[1]);
    //Test if I can grab a value from it and it says that name is undefined but it is clearly their the example above.
    // console.log(coinObj[1].name);


    // send data to the card
    return (
        <div className="container-fluid row">
            <Card name={coinObj[coinsIdArray[0]].name} rank={coinObj[coinsIdArray[0]].rank} price={coinObj[coinsIdArray[0]].quotes["USD"].price} percentChange24={coinObj[coinsIdArray[0]].quotes["USD"].percent_change_24h} />
            <Card name={coinObj[coinsIdArray[1]].name} rank={coinObj[coinsIdArray[1]].rank} price={coinObj[coinsIdArray[1]].quotes["USD"].price} percentChange24={coinObj[coinsIdArray[1]].quotes["USD"].percent_change_24h} />
            <Card name={coinObj[coinsIdArray[2]].name} rank={coinObj[coinsIdArray[2]].rank} price={coinObj[coinsIdArray[2]].quotes["USD"].price} percentChange24={coinObj[coinsIdArray[2]].quotes["USD"].percent_change_24h} />
            <Card name={coinObj[coinsIdArray[3]].name} rank={coinObj[coinsIdArray[3]].rank} price={coinObj[coinsIdArray[3]].quotes["USD"].price} percentChange24={coinObj[coinsIdArray[3]].quotes["USD"].percent_change_24h} />
        </div>
    )
}

export default CardList;

Final Child: 最终孩子:

import React from 'react';

const Card = ({name, rank, price, percentChange24}) => {
    // destructering the data from api to be used.
    // should break up props first but I am trouble shooting other stuff.....................!
    // const {name, rank, price, percentChange24} = props;
    return (
        <div className="card shadow" style={{width: '18rem'}}>
            <img alt='coin/stock logo' src='https://en.bitcoin.it/w/images/en/2/29/BC_Logo_.png' className="mx-auto card-img-top w-50 h-50" />
            <div className="card-body">
                <h2 className="card-title text-center">{name}</h2>
                <h5 className="text-center">{`Rank: ${rank}`}</h5>
            </div>
            <ul className="list-group list-group-flush">
                <li className="list-group-item">{`Price: $${price.toFixed(2)}`}</li>
                <li className="list-group-item">{`Change over 24hrs: ${percentChange24}%`}</li>
            </ul>

        </div>
    )
}

export default Card;

My first problem was getting the information to pass through to the component from the parent. 我的第一个问题是让信息从父级传递到组件。 I was getting an error saying the coinObj[1].name was undefined. 我收到错误消息,说coinObj [1] .name未定义。 I came to the conclusion that it was trying to get the information before the api had returned. 我得出的结论是,它试图在api返回之前获取信息。 Now I cannot get it to re-render which leave me wondering if I will still have that problem after this is corrected. 现在,我无法重新渲染它,这使我想知道在纠正此问题后是否还会遇到该问题。 Please and thank you for any help. 请并感谢您的任何帮助。

The parsedJSON.data that you get from your network request and put in your state is an object. 从网络请求中获取并处于状态的parsedJSON.data是一个对象。 All objects don't have the length property like arrays do, so !coinObj.length will still evaluate to true once the request has finished. 所有对象都不像数组那样具有length属性,因此一旦请求完成, !coinObj.length仍将评估为true

You could instead eg change the initial value from an empty array to null and check for that in your render method: 您可以例如将初始值从一个空数组更改为null并在render方法中检查它:

class App extends Component {
  state = {
    coinObj: null
  };

  // ...

  render() {
    let { coinObj } = this.state;

    return coinObj === null ? (
      <h2>Loading</h2>
    ) : (
      <div>
        <h1>Coins and Stocks</h1>
        <CardList coinObj={coinObj} />
      </div>
    );
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM