Как работать с вызовами асинхронного сервера в Reactjs 16.7.0 - PullRequest
0 голосов
/ 06 февраля 2019

Как правильно использовать асинхронные методы в качестве реквизита в ReactJ?У меня есть приложение, которое монтирует «приборную панель» компонента, и этот компонент затем загружает два выпадающих меню.Первый выпадающий список заполняется async fetch при методе жизненного цикла componentDidMount.

При изменении первого раскрывающегося списка запускается асинхронный обработчик событий, и предполагается, что свойство состояния selectedAId должно быть установлено.Если я отлаживаю это в браузере, я вижу этот набор свойств.После того, как состояние установлено, тот же обработчик событий также вызывает метод асинхронного сервера, чтобы получить некоторые данные, основанные на свойстве состояния selectedAId.

Если затем перейти к методу асинхронного сервера getEntitledSites, параметрпередано методу "0" вместо значения, которое я ранее видел, установленного в обработчике событий.

Вот краткое изложение кода:

https://gist.github.com/thehme/c4b5a958ef1a6e5248f697375c9cb84b#file-api-ts-L15

api.ts

class Api {
...

async getEntitledForA() {
    try {
        const orgsResponse = await fetch('/api/v1/orgs');
        const orgResponseJson = await orgsResponse.json();
        return orgResponseJson.data;
    } catch (err) {
        console.error(err);
        return null;
    }
}

async getEntitledSites(orgId: number) {
    try {
        const sitesResponse = await fetch('/api/v1/study/' + orgId + '/sites');
        const sitesResponseJson = await sitesResponse.json();
        return sitesResponseJson;
    } catch (err) {
        console.error(err);
        return null;
    }
}
}

export default new Api();

dashboard.jsx

import React, {Component} from 'react';
import SelectDropDownA from '../components/SelectDropDownA';
import SelectDropDownB from '../components/SelectDropDownB';
import SelectDropDownC from '../components/SelectDropDownC';

class CreateDashboard extends Component {
    constructor() {
        super();

        this.state = {
            organizations: [],
            sites: [],
            selectedAId: "0",
            selectedBId: "0",
            selectedCId: "0",
            showBMenu: false
        }

    }

    async componentDidMount() {
        let organizations = await Api.getEntitledForA();
        this.setState({ organizations });
    }

    async onSelectedOrgChange(selectedOrgId) {
        if (selectedOrgId !== 0) { 
            this.setState({ selectedAId });
            let sitesData = await Api.getEntitledSites(this.state.selectedAId);
            this.setState({ 
                sites: sitesData.sites,
                showSitesMenu: true
            });
        }
    }

    ...


    render() {
        return (
            <div className="panel">
                <div className="insidePanel">
                    <SelectStudyDropDown 
                        onChange={e => this.onSelectedOrgChange(e.target.value)}
                        ...
                    />
                </div>
                {this.showSitesMenu && 
                    <div className="insidePanel">
                        <SelectSiteDropDown
                            onChange={e => this.onSelectedSiteChange(e.target.value)}
                            ...
                        />
                    </div>
                }
            </div>
        )
    }
}

export default CreateDashboard;

Мне интересно, связано ли это с тем, как я использую async/await или с привязкой метода onChange.

РЕШЕНИЕ: В моем конкретном случае мне не нужно this.state устанавливать selectedAId перед запуском запроса к серверу, поэтому, передав параметр прямо в запрос, он работает нормально.Затем я могу просто перенести настройку selectedAId на второй экземпляр this.setState.Это не сработало бы, если бы мне нужно было установить selectedAId перед выполнением запроса к серверу, и в этом случае мне пришлось бы ждать окончания настройки this.state, но это не так, поскольку я хочу, чтобы мой серверпросьба начать прямо сейчас.

async onSelectedOrgChange(selectedOrgId) {
    if (selectedOrgId !== 0) { 
        let sitesData = await Api.getEntitledSites(selectedOrgId);
        this.setState({ 
            selectedAId,
            sites: sitesData.sites,
            showSitesMenu: true
        });
    }
}

1 Ответ

0 голосов
/ 06 февраля 2019

this.setState является асинхронным и не ожидаемым (т.е. не возвращает обещание), поэтому, если вы хотите что-то сделать с новым состоянием после того, как оно было установлено, вам нужно сделать это в обратном вызове:

this.setState({ selectedAId }, async () => {
    let sitesData = await Api.getEntitledSites(this.state.selectedAId);
    this.setState({ 
        sites: sitesData.sites,
        showSitesMenu: true
    });
});

Кроме того, в вашем примере onSelectedOrgChange нигде не привязан к this.Однако, если бы это было проблемой, все это сломалось бы задолго до этого, поэтому я полагаю, что вы просто исключили это случайно?


Более того, я бы посоветовал вам извлечь e.target.value из обработчика иПередайте onChange={this.onSelectedOrgChange} как реквизит, потому что в вашем текущем коде вы создаете новый обработчик onChange каждый раз, когда вызывается render.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...