A
A
Alex Ozerov2020-07-16 11:21:54
React
Alex Ozerov, 2020-07-16 11:21:54

Incorrect transmission of props?

Good day! I get exchange rates by email. In order not to make a request twice, transfer the receipt of the object to the parent component. Further, I try to propagate the entire state to the child components. BUT! All properties of the state are transferred correctly EXCEPT for the currencyRate object, which actually contains the "res" object with the data I need. I came to the conclusion that he simply does not have time to mount before I pass it on (maybe I'm wrong). Outputting props to the console from a child element like: "console.log(this.props)" displays six times of which the first two with an empty currencyRate and the remaining four already with the necessary objects. Tell me how to properly display props without losing data?

Project Hierarchy: Parent - Main.js and Child - Rate.js/Calc.js

Main:

import React from 'react';
import './Main.css';
import Rate from './Rate/Rate';
import Calc from './Calc/Calc';

class Main extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            date: `${new Date().getDate()}.0${new Date().getMonth()}.${new Date().getFullYear()}`,
            currencyRate: {},
            div: '',
            nothing: {
                name: 'USD',
                value: '22.54'
            }
        }
        this.currency = ['USD', 'EUR', 'RUR', 'BTC'];
    }
    componentDidMount() {
        this.getRate();
    }
    getRate() {
        fetch('https://api.privatbank.ua/p24api/pubinfo?json&exchange&coursid=5')
            .then(data => {
                return data.json()
            })
            .then(data => {
                let res = {};
                for (let i = 0; i < this.currency.length; i++) {
                    res[this.currency[i]] = data[i];
                }
                this.setState({ currencyRate: { res } })

            }).then(() => {
                let obj = Object.entries(this.state.currencyRate.res).map((item, number) => {
                    return (
                        <div className="rates-info" key={number.toString()}>
                            <div className="rates-info_name" >
                                <p>{item[1].ccy}</p>
                            </div>
                            <div className="rates-info_value">
                                <div className="info_value-buy">
                                    <p>Покупка</p>
                                    <p>{item[1].buy}</p>
                                </div>
                                <div className="info_value-buy">
                                    <p>Продажа</p>
                                    <p>{item[1].sale}</p>
                                </div>
                            </div>
                        </div>
                    )
                })
                this.setState({ div: obj })
            })
    }
    render() {
        return (
            <div className="main">
                <div className="content container color">
                    <Rate rates={this.state} />
                    <Calc rates={this.state} />
                </div>
            </div>
        )
    }
}

export default Main;


Calc:
import React from 'react';
import './Calc.css';

class Calc extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            currencyRate: {}
        }
    }
    static getDerivedStateFromProps(props, state) {
        return { currencyRate: props.rates }
    }


    render() {
        return (
            <div className="main_calc">
                <div className="calc_title">
                    <h2>Калькулятор обмена </h2>
                </div>
                <div className="calc-wrap">
                    <div className="calc_body">
                        <div className="calc_header">
                            <p>Я хочу</p>
                        </div>
                        <div className="body_select">
                            <div className="select_check">
                                <input type="radio" name='rdb' value="Купить" id='1' />
                                <label htmlFor="1">Купить</label>
                                <br />
                                <input type="radio" name='rdb' value="Продать" id='2' />
                                <label htmlFor="2">Продать</label>
                            </div>
                            <div className="select_input">
                                <input type="text" />
                                <select>
                                    <option value="USD">USD</option>
                                    <option value="EUR">EUR</option>
                                    <option value="UAH">UAH</option>
                                    {Object.entries(this.state.currencyRate.res).map((item,number) => {
                                        // остальные вычисления
                                        //Если вместо этого кода запустить console.log(this.props) то обьект currencyRate будет пустым
                                    })}
                                </select>
                            </div>
                            <div className="select_result">
                                <h3>Результат:</h3>
                                <p>EUR 150</p>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

export default Calc;

Answer the question

In order to leave comments, you need to log in

1 answer(s)
T
TRNER, 2020-07-17
@ozerovlife

You are right that he "does not have time to mount". The setState function works asynchronously, and the promise will not wait for it to complete before calling the next .then in the chain, so we have no guarantee that the state will be updated by the next use of the state. In such cases, a callback is usually used, which is passed to setState as the second argument and is called after the state is updated called by this method, but in our case, I think we can update everything at once.

getRate() {
        fetch('https://api.privatbank.ua/p24api/pubinfo?json&exchange&coursid=5')
            .then(data => {
                return data.json()
            })
            .then(data => {
                let res = {};
                for (let i = 0; i < this.currency.length; i++) {
                    res[this.currency[i]] = data[i];
                }

                let obj = Object.entries(res).map((item, number) => {
                    return (
                        <div className="rates-info" key={number.toString()}>
                            <div className="rates-info_name" >
                                <p>{item[1].ccy}</p>
                            </div>
                            <div className="rates-info_value">
                                <div className="info_value-buy">
                                    <p>Покупка</p>
                                    <p>{item[1].buy}</p>
                                </div>
                                <div className="info_value-buy">
                                    <p>Продажа</p>
                                    <p>{item[1].sale}</p>
                                </div>
                            </div>
                        </div>
                    )
                })
                this.setState({ currencyRate: { res }, div: obj });

            });
    }

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question