@ozerovlife
Front-end Developer

Некорректная передача пропсов?

Доброго времени суток! Получаю по апишке курсы валют. Что бы два раза не делать запрос вынес получение обьекта в компонент - родитель. Дальше в дочерние компоненты пытаюсь пропсом передать весь стейт. НО! Все свойства стейта передаються корректно КРОМЕ обьекта currencyRate в котором собственно и есть обьект "res" с нужными мне данными. Пришел к выводу что он просто не успевает вмонтироваться прежде чем я его передаю(возможно я не прав). Вывод пропса в консоль из дочернего элемента типа: "console.log(this.props)" выводит шесть раз из которых первых два с пустым currencyRate а остальные четыре уже с нужными обьектами. Подскажите как правильно вывести пропс без потери данных?

Иерархия проекта: Родитель - Main.js и Дочерние - 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;
  • Вопрос задан
  • 33 просмотра
Решения вопроса 1
@TRNER
Вы правы в том, что он "не успевает вмонтироваться". Функция setState работает асинхронно, и промис не будет дожидаться ее выполнения перед вызовом следующего .then в цепочке, так что у нас нет никаких гарантий на то, что состояние обновится к следующему использованию стейта. В таких случаях обычно используют коллбэк, который передается в setState вторым аргументом и вызывается после обновления состояния, вызванного этим методом, однако в нашем случае, я думаю, можно обновить все за один раз.

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 });

            });
    }
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы