使用 fetch API 时在 AJAX 调用期间显示微调器
Posted
技术标签:
【中文标题】使用 fetch API 时在 AJAX 调用期间显示微调器【英文标题】:Display spinner during AJAX call when using fetch API 【发布时间】:2017-10-03 04:09:00 【问题描述】:在我的项目中,我正在迁移到 React,因此不加载 JQuery。由于我不再使用 JQuery,因此对于 AJAX 调用,我使用的是 fetch。使用 JQuery,我可以挂钩 AJAX 调用的开始和结束,因此很容易将光标更改为微调器。我在 fetch 中找不到类似的钩子。除了在每个单独的 AJAX 调用中更改它之外,还有其他方法吗?
大量谷歌搜索只是不断寻找关于... JQuery 的答案。
【问题讨论】:
全局挂钩在 jQuery 中是个坏主意,这并没有停止。为您的应用程序正在执行的每个单独请求执行微调器。 @Bergi 为什么全局挂钩是个坏主意? 因为您可能正在使用一个库,该库执行自己的fetch
请求,并且您不想拦截它们。或者您可能希望不再拦截所有您自己的请求。为了提高可维护性,只需编写自己的包装函数来处理微调器,然后在需要使用微调器发出请求的任何地方调用它。
【参考方案1】:
你去吧,我认为代码是不言自明的:
// Store a copy of the fetch function
var _oldFetch = fetch;
// Create our new version of the fetch function
window.fetch = function()
// Create hooks
var fetchStart = new Event( 'fetchStart', 'view': document, 'bubbles': true, 'cancelable': false );
var fetchEnd = new Event( 'fetchEnd', 'view': document, 'bubbles': true, 'cancelable': false );
// Pass the supplied arguments to the real fetch function
var fetchCall = _oldFetch.apply(this, arguments);
// Trigger the fetchStart event
document.dispatchEvent(fetchStart);
fetchCall.then(function()
// Trigger the fetchEnd event
document.dispatchEvent(fetchEnd);
).catch(function()
// Trigger the fetchEnd event
document.dispatchEvent(fetchEnd);
);
return fetchCall;
;
document.addEventListener('fetchStart', function()
console.log("Show spinner");
);
document.addEventListener('fetchEnd', function()
console.log("Hide spinner");
);
这是一个活生生的例子:https://jsfiddle.net/4fxfcp7g/4/
【讨论】:
请注意fetchEnd
在整个响应正文加载之前触发
这正是我想到的那种东西,给你一箱啤酒!谢谢!
很高兴它帮助了你!只要确保使用我的 sn-p 的最新编辑。
@EtienneMartin 最新的似乎被破坏了......对休息端点的调用以错误“TypeError:已读”终止
你是对的,我的错。我恢复到以前的版本。【参考方案2】:
在 thenable 中获取,可以在 then() 中添加 spinner stop 函数,在收到响应后调用。并将其包装在另一个函数中,用于 headers 和 hooking。
function ajax(someUrl, method)
var myHeaders = new Headers();
var myInit =
method: method,
headers: myHeaders
;
showSpinner();
return fetch(someUrl, myInit).then(function(response)
//... do some with response
hideSpinner();
return response;
).catch(function(error)
//... tell the user the request failed and hide the spinner
hideSpinner();
return error;
);
ajax('example.com').then(function(response)
// ...
).catch(function(error)
// show error
);
【讨论】:
是的,谢谢,我知道,但这涉及在每个 AJAX 调用中放置 showSpinner() 和 hideSpinner()... 我认为你误解了这个问题,OP 想要挂钩每个 fetch 调用的开始和结束。 @JimArcher 确实......也许将它包装在某个函数中?并调用该包装器而不是获取?我已经改变了例子。 这是正确的想法,但@EtienneMartin 成功了!【参考方案3】:我发现使用手动设置“加载”标志的主要问题 true / false 是很容易错误地跳过设置为 false 标志并且您的应用程序想要挂起),另一方面我不想在并行调用多个 ajax 请求时搞砸,这甚至当您想要跟踪其中一些时会更加困难,但在其他情况下您想要发出静默请求。
我创建了一个名为 react-promise-tracker 的微型库,以更自动的方式处理此问题。它是如何工作的
安装承诺跟踪器
npm install react-promise-tracker --save
实现一个简单的加载指示器组件(你可以为其添加你需要的样式),并用 promiseTrackerHoc
包裹它import promiseTrackerHoc from 'react-promise-tracker';
const InnerLoadingIndicator = props => (
props.trackedPromiseInProgress &&
<h1>Hey some async call in progress ! Add your styling here</h1>
);
export const LoadingIndicator = promiseTrackerHoc(InnerLoadingIndicator);
在您的应用程序根组件中实例化它:
render(
<div>
<App />
<LoadingIndicator/>
</div>,
document.getElementById("root")
);
当你想跟踪一个 fetch 或任何基于 promise 的调用(包括 async/await)时,只需用 react-promise-tracker 函数 trackPromise 包装它:
import trackPromise from 'react-promise-tracker';
export class MyComponent extends Component
componentWillMount()
trackPromise(
userAPI.fetchUsers()
.then((users) =>
this.setState(
users,
)
)
);
// ...
更多资源: - 分步教程(包括添加漂亮的微调器):https://www.basefactor.com/react-how-to-display-a-loading-indicator-on-fetch-calls
实时样本:https://stackblitz.com/edit/react-promise-tracker-default-area-sample
Github 页面:https://github.com/Lemoncode/react-promise-tracker
【讨论】:
【参考方案4】:当fetch
最初发生时你可以做什么,你setState
加载为true
。然后,一旦 fetch 完成,你可以setState
因为加载是false
。然后根据当前状态显示微调器。
例如,
class SomeComponent extends React.Component
constructor(props)
super(props);
this.state = loading: false ;
loadData(e)
e.preventDefault();
this.setState( loading: true );
fetch(....).then( res => res.json()).then( resJson =>
// do other stuff here.
this.setState( loading: false );
);
render()
return (
<div>
<DisplayComponent />
<button onClick=this.loadData>Click Me</button>
this.state.loading ? <Spinner /> : null
</div>
);
您可以查看react conditional rendering
【讨论】:
以上是关于使用 fetch API 时在 AJAX 调用期间显示微调器的主要内容,如果未能解决你的问题,请参考以下文章
.NET Core 3.1 中使用 Fetch API 的 Ajax 调用
试图将 jquery AJAX 转换为 Fetch API,如何设置RequestHeader?
基于Promise对象的新一代Ajax API--fetch