【问题标题】:When state is updated, component does not re-render with updated state (REACT)更新状态时,组件不会使用更新的状态重新渲染 (REACT)
【发布时间】:2021-06-04 16:35:41
【问题描述】:

好吧,让我开始吧,这段代码可能看起来很乱,但我认为问题很简单。

因此,每当我更改以下“TitleCards”子组件的父级中的状态时,子组件中的状态也会发生更改,但“TitleCards”组件的渲染方法中的portfolioTotal 值不会根据更改重新计算状态。我认为它与异步功能有关,但我不确定。

有什么想法吗?我想要的只是当子组件中的状态发生变化时(我可以使用开发工具看到它正在发生变化),以便组件自动重新渲染/重新计算更改后的状态的投资组合。

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;

如果有任何帮助,状态更改并传递给 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;

【问题讨论】:

  • 在这种情况下你可以使用事件监听器。因为子组件的状态变化不会直接触发重新渲染周期。
  • 我所理解的只是 TitleCards 是您的子组件,状态值的变化 portfolioTotal 正在触发 TitleCards 中的重新渲染,但不会在 UserInput 中触发。如果我理解正确还是相反?
  • 当来自 prop 的信息发生变化时,组件将重新渲染,但没有任何东西会改变portfolioTotal。它保持在子组件的状态,并且您设置它的唯一位置是在安装时执行一次的 componentDidMount 中。如果你想重新计算portfolioTotal,你应该将componentDidMount更改为componentDidUpdate,以便在props更改时执行它。

标签: javascript reactjs state


【解决方案1】:

componentDidMount 每次坐骑只触发一次。如果你想在每次组件重新渲染时运行一些东西,你需要componentDidUpdate。看看这个lifecycle diagram用什么方法。

componentDidUpdatethis.setState 一起使用时要小心。如果在 componentDidUpdate 中每个周期都盲目地更新 state,就会触发无限循环。 (详情请见this answer。)

【讨论】:

  • 你知道包装 componentDidUpdate 的条件应该包括什么吗?我尝试了以下但得到了无限循环。 if 语句中的第二个值是我丢失的内容。 ` componentDidUpdate() { if (this.state.portfolioTotal == ???? ) { this.totalPortfolio() .then(portfolioTotal => { this.setState({portfolioTotal }); }) .catch(error => { // 在此处添加任何所需的错误处理/消息 }); } }`
  • 没有看到你的完整代码和知道你的意图,我不能肯定地告诉你。想想这样的假设:只有当你想获得一个新的投资组合时,它才应该是正确的。也许这意味着像if (Boolean(this.state.portfolioTotal)) 这样的东西,只有在没有portfolioTotal 的情况下才会评估为假。也许这意味着类似if (moreThan30SecondsAgo(lastFetchTime))
猜你喜欢
  • 2021-05-19
  • 2022-01-26
  • 2019-02-27
  • 2020-09-05
  • 1970-01-01
  • 2020-10-24
  • 2018-06-05
  • 2023-03-09
相关资源
最近更新 更多