简体   繁体   English

当 state 更新时,组件不会使用更新的 state 重新渲染(反应)

[英]When state is updated, component does not re-render with updated state (REACT)

Ok so let me just start with this code probably looks like a mess but the problem is pretty simple I think.好的,让我从这段代码开始,可能看起来很乱,但我认为问题很简单。

So whenever I change the state in the parent of the below 'TitleCards' child component, the state changes in the child component too but the portfolioTotal value in the render method of the 'TitleCards' component does not recalculate based on the changed state. So whenever I change the state in the parent of the below 'TitleCards' child component, the state changes in the child component too but the portfolioTotal value in the render method of the 'TitleCards' component does not recalculate based on the changed state. I think it has something to do with the async function, but I'm not sure.我认为这与异步 function 有关,但我不确定。

Any ideas?有任何想法吗? All I want is when the state changes in the child component (which I can see with dev tools that it is changing), for the component to automatically re-render/recalculate portfolioTotal with the changed state.我想要的只是当子组件中的 state 发生变化时(我可以使用开发工具看到它正在发生变化),以便组件使用更改后的 state 自动重新渲染/重新计算投资组合总计。

import "./StockCard.css";
import { IEX } from "./IEX.js";
import moment from 'moment';
import Folder from "./folder.png";
import MoneyBag from "./money-bag.png";
import Handshake from "./hand-shake.png";
import add from "./add.png";
import NumberFormat from 'react-number-format';

const LOGO_API = "https://eodhistoricaldata.com/img/logos/US/";

class TitleCards extends Component {
    constructor(props){
        super(props)
        this.arr = this.totalPortfolio();
        this.state ={
            portfolioTotal: '',
            WhenThisChangesShouldntTheComponentReRender: this.props.info,
        }
        this.totalPortfolio = this.totalPortfolio.bind(this);
        this.getIntradayPrice = this.getIntradayPrice.bind(this);

    }

    static defaultProps = {
        TitleCardInfo: [
          { name: "Portfolio", ticker: "DIA"}, 
          { name: "Total Return", ticker: "SPY"}, 
          { name: "Positions Held", ticker: "IWM"}, 
          { name: "Add Position", ticker: "Gold"},],
      }

    async getIntradayPrice(tick) {
        const resp = await fetch(`${IEX.base_url}/stock/${tick}/intraday-prices?chartLast=1&token=${IEX.api_token}`);
        return resp.json();
      }

    async totalPortfolio() {
        const { info } = this.props;
        const respPromises = info.map(({ tick }) => this.getIntradayPrice(tick));
        const respArrays = await Promise.all(respPromises);
        const result = respArrays.reduce((acc, val, index) => acc + val[0].close * info[index].amtPurch, 0);
        return result;
      }
      
    componentDidMount() {
        this.totalPortfolio()
          .then(portfolioTotal => {
            this.setState({
              portfolioTotal
            });
          })
        .catch(error => {
            // add any required error handling/messaging here
        });
    }

    render(){  
        const { portfolioTotal } = this.state;
        return(
            <div className="positioning">
                <div className="StockCardTitle">
                    <img src={Folder} className="StockCardTitle-image" />  
                    {portfolioTotal}
                </div>
            </div>
        )
    }
}
export default TitleCards;

Parent Component where state changes and is passed down to TitleCard Component, if its of any help. state 更改并传递给 TitleCard 组件的父组件(如果有帮助的话)。

import React, { Component } from 'react';
import StockCard from "./StockCard";
import TitleCards from "./TitleCards";
import { IEX } from "./IEX.js";

const LOGO_API = "https://eodhistoricaldata.com/img/logos/US/";

class UserInput extends Component {
    constructor(props){
        super(props)
        this.state ={
            tickerName: "",
            sAmtPurch: "",
            sPurchPrice: "",
            sDatePurch: "",
            tickerList: [
                { tick: "AAPL", amtPurch: 50, purchPrice: 10, datePurch: "01/01/2021"},
                { tick: "GOOG", amtPurch: "40", purchPrice: "10", datePurch: "01/01/2021"},
                { tick: "TSLA", amtPurch: "40", purchPrice: "10", datePurch: "01/01/2021"},
                { tick: "J", amtPurch: "40", purchPrice: "10", datePurch: "01/01/2021"},
                { tick: "AMZN", amtPurch: "40", purchPrice: "10", datePurch: "01/01/2021"},
                { tick: "FB", amtPurch: "40", purchPrice: "10", datePurch: "01/01/2021"},
                { tick: "BABA", amtPurch: "40", purchPrice: "10", datePurch: "01/01/2021"},
                { tick: "JNJ", amtPurch: "40", purchPrice: "10", datePurch: "01/01/2021"},
                { tick: "JPM", amtPurch: "40", purchPrice: "10", datePurch: "01/01/2021"},
                { tick: "XOM", amtPurch: "30", purchPrice: "10", datePurch: "01/01/2021"},
                ],
            data4: {}
        }
        this.handler = this.handler.bind(this)
    }

    handleSubmit = (event) => {
        event.preventDefault()
        // Initialize state into variables 
        const tickerToBeAdded = { tick: this.state.tickerName, amtPurch: this.state.sAmtPurch, purchPrice: this.state.sPurchPrice, datePurch: this.state.sDatePurch};
        const tickerList = this.state.tickerList;
        
        // Apend tickerList with inputed ticker
        const length = tickerList.length;
        tickerList[length] = tickerToBeAdded;
        this.setState({
            tickerList: tickerList
        })
    }
    handleInputChange = (event) => {
        event.preventDefault()
        // Store Input in State
        this.setState({
            [event.target.name]: event.target.value
        })
    }

    componentDidMount() {
    // query the api
    const url4 = `${IEX.base_url}/stock/${this.state.tickerList.tick}/intraday-prices?chartLast=1&token=${IEX.api_token}`;
    fetch(url4)
      .then((response) => response.json())
      .then((data4) => {
        this.setState({
          data4: data4[data4.length - 1],
        });
      });
    }

    render () {

        return (
            <div>
                <form onSubmit={this.handleSubmit}>
                    <p><input type='text' placeholder='Stock Ticker' name='tickerName' onChange={this.handleInputChange}/></p>
                    <p><input type='text' placeholder='Shares' name='sAmtPurch' onChange={this.handleInputChange}/></p>
                    <p><input type='text' placeholder='Purchase Price' name='sPurchPrice' onChange={this.handleInputChange}/></p>
                    <p><button>Send Message</button></p>
                </form>

                <div className="Charts">
                        <TitleCards info={this.state.tickerList}/>
                </div>
            </div>
        )
    }
}

export default UserInput;

componentDidMount only fires once per mount. componentDidMount每次安装只触发一次。 If you want to run something every time the component re-renders, you need componentDidUpdate .如果你想在每次组件重新渲染时运行一些东西,你需要componentDidUpdate Take a look at this lifecycle diagram for what method to use.看看这个 生命周期图,了解使用什么方法。

Be careful when using componentDidUpdate with this.setState .componentDidUpdatethis.setState一起使用时要小心。 If you blindly update state every cycle in componentDidUpdate, you'll trigger an infinite loop.如果你在componentDidUpdate中每个周期都盲目地更新state,就会触发死循环。 (See this answer for details.) (有关详细信息,请参阅此答案。)

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

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