使用外部文件

时间:2019-01-10 18:43:28

标签: javascript reactjs asynchronous callback

我正在使用react的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 :(得分:1)

如果我正确理解了您的问题,则希望将请求函数移至一个单独的文件,但是在该函数中,您将使用“ 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;
}

在App.js中

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

这里是一个很好的答案的链接,该讨论讨论将回调转换为Promise以实现更同步的执行。绝对看看接受的答案中的“ nodebacks”示例:How do I convert an existing callback API to promises?