我正在使用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})
}
但是,没有成功。也许是创建类组件的唯一方法吗?
答案 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?