Рефакторинг вложил асинхронный обратный вызов в реагирующий компонент componentDidMount () с использованием внешнего файла - PullRequest
0 голосов
/ 10 января 2019

Я использую реагирующий componentDidMount(), который содержит много кода и выполняет два обратных вызова. В конце концов, в самом внутреннем обратном вызове (то есть во втором) я выполняю this.setState({}).

Минимальный код

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = { data: {} };
  }

  requests() {
    fooCallback.request({ data: { query: userQuery } }).subscribe(({ jsonResp1 }) => {

      // 100 lines of data processing with jsonResp1


      // second Callback
      barCallback.request({ data: { string: userString } }).subscribe(({ jsonResp2 }) => {

        // 200 lines of data processing with jsonResp2
        this.setState({ data: processedData })

      });
    });


    componentDidMount() {
      this.requests();
    }
  }

  render() {
    // ...
    return (
          // ...
        );
  }

}

Поскольку метод request() очень велик, он раздувает мой основной компонент контейнера App. Я уже пытался создать внешний файл js (default export function ...) и импортировал его в свой App.js. Тем не менее, это было невозможно, вероятно, из-за асинхронной природы метода.

Можно ли как-нибудь уменьшить мой App.js?

Редактировать

Во многих вариантах я пытался создать файл external.js:

external.js

export default async () => {
    return fooCallback.request({ data: { query: userQuery } }).subscribe(({ jsonResp1 }) => {

      // 100 lines of data processing with jsonResp1


      // second Callback
      barCallback.request({ data: { string: userString } }).subscribe(({ jsonResp2 }) => {

        // 200 lines of data processing with jsonResp2
        return processedData

      });

    return barCallback;

    });

... и затем импортировать

App.js

import getData from './js/getData.js'
// ...
async componentDidMount() {
  const response = await this.getData()
  this.setState({data: response})
}

Пока нет успеха. Может быть, это единственный способ создать компонент класса?

1 Ответ

0 голосов
/ 10 января 2019

Если я правильно понимаю ваш вопрос, вы хотите переместить функцию запроса в отдельный файл, но внутри функции вы используете "this.setState", который находится вне области видимости компонентов.

Вы правы, чтобы убрать эту логику из компонента. С обратными вызовами иногда сложно работать, особенно когда обратные вызовы зависят от других обратных вызовов, и так далее.

Не было бы неплохо, если бы обратные вызовы действовали синхронно? Вы можете смоделировать это, обернув обратные вызовы в Promises и ожидая результатов обратных вызовов для разрешения. Таким образом, ваша программа будет ожидать полного выполнения первого обратного вызова и возвращать данные перед выполнением следующего обратного вызова (который вы собирались вложить), для которого требовался вывод первого.

Файл утилиты будет выглядеть примерно так:

function processRespOne(fooCallback, userQuery) {
  return new Promise((resolve, reject) => {
    fooCallback.request({ data: { query: userQuery } }).subscribe(({ jsonResp1 }) => {
      // ...process jsonResp1
      // by resolving this data, it acts like a standard function "return" if the invoking expression awaits it
      resolve(processedData);
    });
  });
}

function processRespTwo(respOneData, barCallback, userString) {
  return new Promise((resolve, reject) => {
    barCallback.request({ data: { string: userString } }).subscribe(({ jsonResp2 }) => {
      // process jsonResp2 with the output of respOneData
      resolve(processedData);
    });
  });
}


// here I define the function "async" so i can use the "await" syntax, so my asynchronous function acts synchronous 
// Async functions return promises. So caller's can await this function.
export async function requests(fooCallback, userQuery, barCallback, userString) {
  const respOneData = await processRespOne(fooCallback, userQuery);
  const results = await processRespTwo(respOneData, barCallback, userString)

  // anyone who is "await"ing this function will get back results
  return results;
}

In App.js

import { requests } from './js/getData.js';
//...
   async componentDidMount() {
     const results = await requests(fooCallback, userQuery, barCallback, userString);
     this.setState({ results });
   }

Вот ссылка на действительно хороший ответ, в котором обсуждается преобразование обратных вызовов в обещания для более синхронного выполнения. Обязательно посмотрите на пример "nodebacks" в принятом ответе: Как преобразовать существующий API обратного вызова в обещания?

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