我目前正在构建一个Relay / React网络应用。除了一个例外,它非常简单。当我的任何组件发出网络请求时,我无法弄清楚如何获得全局通知。当有网络活动的时候,我正在跳到我的应用程序顶部添加一个微调器,因为我的一些突变需要很长时间才能加载。
这是我尝试解决此问题,但它仅适用于新路由页面加载。
Consumer<BigDecimal>
理想情况下,我可以获得一些回调,我可以传递给我的App组件,它会呈现我的所有页面页眉和页脚。任何有关这方面的帮助将不胜感激。我已经在互联网上待了一段时间,试图找到一个很好的解决方案。
答案 0 :(得分:1)
您还可以尝试添加自定义Relay Network Layer,在每个请求中呈现加载指示符组件。我认为主要考虑的是全球&#34;加载指标不仅涉及指标的设计,还涉及其对全球UI的影响。它会阻止UI吗?只是它的一部分吗?它会向上/向下移动其他元素吗?等等。
与此同时,您可以执行以下操作:
handleSubmit(event) {
event.preventDefault();
this.setState({isLoading: true});
this.props.relay.commitUpdate(
new LoginMutation({
email: this.refs.email.value,
password: this.refs.password.value
}), {
onSuccess: response => {
Auth.login(response.login.accessToken);
const { location, router } = this.props;
if (location.state && location.state.nextPathname) {
router.replace(location.state.nextPathname)
} else {
router.replace('/')
}
},
onFailure: transaction => {
this.setState({hasError: true});
this.setState({isLoading: false});
}
}
);
}
上面的摘录摘自here。您可以在该回购中看到其余的逻辑。
答案 1 :(得分:0)
您可以在react中创建自定义微调器组件,并根据您的数据加载状态显示或隐藏微调器。
这方面的一个例子可以是 -
你的Spinner组件可能是这样的 -
let SpinMe
= (
<div className="spinner-container">
<div className="loader">
<svg className="circular">
<circle className = "path"
cx = "50"
cy = "50"
r = "20"
fill = "none"
strokeWidth = "3"
strokeMiterLimit = "10"
/>
</svg>
</div>
</div>
);
此微调器组件应比其他组件稍高z-index
,以便在加载时,用户无法单击其他组件或与其他组件交互。
同样在造型中展示了一些透明的深色背景。
例如
.spinner-container {
position : absolute;
background-color : rgba(12, 12, 12, 0.61);
width : 100%;
min-height : 100%;
background-size : 100% 100%;
text-align : center;
z-index : 3;
top : 0;
left : 0;
}
现在您想要使用微调器的另一个组件,并且您希望在此组件中发出网络请求。
import React from 'react';
class SpinTestComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading:false
};
}
sendNetworkRequest(URL, dataToSend) {
return $.ajax({
type : 'POST',
url : URL,
data : JSON.stringify(dataToSend),
dataType : 'json'
});
}
componentDidMount() {
const URL = "test url";
const dataToSend = { param1:"val", param2:"val" };
this.setState({isLoading:true});
this.sendNetworkRequest(dataToSend)
.then(
() => {
// success response now remove spinner
this.setState({isLoading:false});
},
() => {
// error response again remove spinner and
// show error message to end user
this.setState({isLoading:false});
});
}
render() {
return (
<div>
{ this.state.isLoading ? <SpinMe/> : null }
<div>
<h1>
Remaining Component structure
or Jsx
</h1>
<p>
To be show after loading is done.
</p>
</div>
</div>
);
}
}
export default SpinTestComponent;
答案 2 :(得分:0)
我最终扩展了Relay的默认网络层,以便我可以制作一些我的主要根组件监听的Flux事件。如果我愿意,这允许我将所有加载和错误消息处理在一个地方。
这是我的最终解决方案。不确定它是最干净的,但效果很好。
import Relay from "react-relay";
import RelayMutationRequest from "react-relay/lib/RelayMutationRequest";
import AppDispatcher from "./AppDispatcher";
export default class CustomNetworkLayer extends Relay.DefaultNetworkLayer {
constructor(uri, init)
{
super(uri, init);
}
networkLoadingEvent()
{
AppDispatcher.dispatch({
actionType: 'LOADING'
});
}
networkDoneLoadingEvent()
{
AppDispatcher.dispatch({
actionType: 'DONE_LOADING'
});
}
networkErrorEvent(error)
{
AppDispatcher.dispatch({
actionType: 'ERROR',
payload: error
});
}
sendQueries(requests)
{
this.networkLoadingEvent();
return Promise.all(requests.map(request => (
this._sendQuery(request).then(
result => result.json()
).then(payload =>
{
if (payload.hasOwnProperty('errors')) {
const error = CustomNetworkLayer.createRequestError(request, '200', payload);
this.networkErrorEvent(payload.errors[0].message);
request.reject(error);
} else {
if (!payload.hasOwnProperty('data')) {
const error = new Error(
'Server response was missing for query ' +
`\`${request.getDebugName()}\`.`
);
this.networkErrorEvent(error);
request.reject(error);
} else {
this.networkDoneLoadingEvent();
request.resolve({response: payload.data});
}
}
}).catch(
error =>
{
this.networkErrorEvent(error);
request.reject(error)
}
)
)));
}
sendMutation(request)
{
this.networkLoadingEvent();
return this._sendMutation(request).then(
result => result.json()
).then(payload =>
{
if (payload.hasOwnProperty('errors')) {
const error = CustomNetworkLayer.createRequestError(request, '200', payload);
this.networkErrorEvent(payload.errors[0].message);
request.reject(error);
} else {
this.networkDoneLoadingEvent();
request.resolve({response: payload.data});
}
}).catch(
error =>
{
this.networkErrorEvent(error);
request.reject(error)
}
);
}
/**
* Formats an error response from GraphQL server request.
*/
static formatRequestErrors(request, errors)
{
const CONTEXT_BEFORE = 20;
const CONTEXT_LENGTH = 60;
const queryLines = request.getQueryString().split('\n');
return errors.map(({locations, message}, ii) =>
{
const prefix = (ii + 1) + '. ';
const indent = ' '.repeat(prefix.length);
//custom errors thrown in graphql-server may not have locations
const locationMessage = locations ?
('\n' + locations.map(({column, line}) =>
{
const queryLine = queryLines[line - 1];
const offset = Math.min(column - 1, CONTEXT_BEFORE);
return [
queryLine.substr(column - 1 - offset, CONTEXT_LENGTH),
' '.repeat(Math.max(0, offset)) + '^^^',
].map(messageLine => indent + messageLine).join('\n');
}).join('\n')) :
'';
return prefix + message + locationMessage;
}).join('\n');
}
static createRequestError(request, responseStatus, payload)
{
const requestType =
request instanceof RelayMutationRequest ? 'mutation' : 'query';
const errorReason = typeof payload === 'object' ?
CustomNetworkLayer.formatRequestErrors(request, payload.errors) :
`Server response had an error status: ${responseStatus}`;
const error = new Error(
`Server request for ${requestType} \`${request.getDebugName()}\` ` +
`failed for the following reasons:\n\n${errorReason}`
);
error.source = payload;
error.status = responseStatus;
return error;
}
}
然后在我的index.js文件中执行此操作:
Relay.injectNetworkLayer(new CustomNetworkLayer("/graphql",
{
fetchTimeout: 35000, // timeout after 35 seconds
retryDelays: [2000] // retry after 2 seconds
}));
快速说明:AppDispatcher只是一个flux js调度程序,我正在我的主包装器组件中监听这些事件。
希望这可以帮助其他人。我当然花了太多时间在这上面。
还要感谢帮助我解决这个问题的所有人。