折腾:
【未解决】Antd Pro中点击提交后禁止再点击按钮
期间,现有的Reactjs的Antd Pro中的相关网络请求的代码是:
this.props.dispatch({
type: 'script/submitScript',
payload: params,
}).then(() => {
this.props.dispatch(routerRedux.push('/script/script-list'));
});->
src/models/script.js
*submitScript({ payload }, { call }) {
yield call(createScript, payload);
message.success('新建剧本成功');
},->
src/services/api.js
export async function createScript(params) {
return request(`${apiPrefix}/scripts/`, {
method: 'POST',
body: params,
headers: constructHeaders(),
});
}->
src/utils/request.js
export default function request(url, options) {
const defaultOptions = {
credentials: 'include',
};
const newOptions = { ...defaultOptions, ...options };
if (newOptions.method === 'POST' || newOptions.method === 'PUT' || newOptions.method === 'PATCH') {
if (!(newOptions.body instanceof FormData)) {
newOptions.headers = {
Accept: 'application/json',
'Content-Type': 'application/json; charset=utf-8',
...newOptions.headers,
};
newOptions.body = JSON.stringify(newOptions.body);
} else {
// newOptions.body is FormData
newOptions.headers = {
Accept: 'application/json',
...newOptions.headers,
};
}
}
return fetch(url, newOptions)
// .then(debugResponse)
.then(checkStatus)
.then(response => {
if (newOptions.method === 'DELETE' || response.status === 204) {
return response.text();
}
if (url.includes('word')) {
window.open(url);
}
return response.json();
})
.catch(e => {
console.log(`url=${url} -> error=`, e);
const { dispatch } = store;
const status = e.name;
if (status === 401) {
dispatch({
type: 'login/logout',
});
return;
}
if (status === 403) {
dispatch(routerRedux.push('/exception/403'));
return;
}
if (status <= 504 && status >= 500) {
dispatch(routerRedux.push('/exception/500'));
return;
}
if (status >= 404 && status < 422) {
dispatch(routerRedux.push('/exception/404'));
}
});
}很明显,此处的http的request,当出错时,最终都被catch中去统一处理掉异常了
从而没有让fetch的调用者直到异常,也就无法自己掌控
比如此处,希望在异常时,去掉之前按钮的disable,允许重新被点击
所以此处,目前能想到的,最完美的情况是:
fetch调用后台api返回后,不论是exception出错,还是正常response返回,都有个callback
而此处的调用接口时,都是dispatch一个字符串
然后跳转到负责的model去处理的
现在正常返回是有callback的
所以要想办法去在现有基础上加个exception的callback
antd pro api 异常 回调函数
this.props.dispatch({
type: '***',
payload: '***',
callback: () => {
// callback function
}
})去找找此处是否真的支持callback
才发现是自己去添加的:
*fetch({ payload, callback }, { call, put }) {
// request here
if (callback) callback() // ** 回调函数 **
})试试直接传递callback会发生什么
if (this.isEditMode()){
dispatchDict = {
type: 'script/updateScript',
payload: params,
scriptID: this.state.curScriptId,
callback: (resp) => {
console.log("updateScript callback: resp=", resp)
}
}
} else {
dispatchDict = {
type: 'script/submitScript',
payload: params,
callback: (resp) => {
console.log("submitScript callback: resp=", resp)
}
}
}
console.log("dispatchDict=", dispatchDict)
this.props.dispatch(dispatchDict).then(() => {
this.props.dispatch(routerRedux.push('/script/script-list'));
})当然没有任何反应,毕竟接口不支持。
去添加支持errorCallback
【总结】
最后采用的是:
虽然不完美,但是凑合可以达到基本的效果:
不论是返回正常数据还是出错,都可以回调函数的方式:
src/routes/Script/ScriptCreateEdit.js
params.dialogs = dialogItemList
console.log('params=', params)
const okOrErrorCallback = (errOrData) => {
console.log("okOrErrorCallback: errOrData=", errOrData)
if(!errOrData) {
console.log("okOrErrorCallback: Omit response empty")
return
}
this.setState({
isSubmitting: false,
isDisableSubmit: false,
})
console.log(`okOrErrorCallback: isSubmitting=${this.state.isSubmitting},isDisableSubmit=${this.state.isDisableSubmit}`)
if(errOrData instanceof Error) {
const errMsg = this.state.curPageTitle + "出错:" + `${errOrData}`
console.log(errMsg)
message.error(errMsg)
} else {
const okMsg = this.state.curPageTitle + "成功"
console.info(okMsg)
message.info(okMsg)
this.props.dispatch(routerRedux.push('/script/script-list'))
}
}
let dispatchDict
if (this.isEditMode()){
dispatchDict = {
type: 'script/updateScript',
payload: params,
scriptID: this.state.curScriptId,
okOrErrorCallback: okOrErrorCallback,
}
} else {
dispatchDict = {
type: 'script/submitScript',
payload: params,
okOrErrorCallback: okOrErrorCallback,
}
}
console.log("dispatchDict=", dispatchDict)
this.setState({
isSubmitting: true,
isDisableSubmit: true,
})
console.log(`Now will submit: isSubmitting=${this.state.isSubmitting},isDisableSubmit=${this.state.isDisableSubmit}`)
// const afterSubmitCallback = (resp) => {
// console.log("afterSubmitCallback: resp=", resp)
// }
// this.props.dispatch(dispatchDict).then(afterSubmitCallback())
this.props.dispatch(dispatchDict)src/models/script.js
*submitScript({ payload, okOrErrorCallback}, { call }) {
console.log("submitScript: payload=", payload, ", okOrErrorCallback=", okOrErrorCallback)
const resp = yield call(createScript, payload, okOrErrorCallback)
console.log("after createScript: resp=", resp)
if(okOrErrorCallback) {
okOrErrorCallback(resp)
}
},
*updateScript({ payload, scriptID, okOrErrorCallback}, { call }) {
console.log("updateScript: payload=", payload, ", scriptID=", scriptID, ", errorCallback=", okOrErrorCallback)
const resp = yield call(updateScript, payload, scriptID);
console.log("after updateScript: resp=", resp)
if(okOrErrorCallback) {
okOrErrorCallback(resp)
}
},src/services/api.js
export async function createScript(params, okOrErrorCallback) {
console.log("createScript: params=", params, ", okOrErrorCallback=", okOrErrorCallback)
return request(
`${apiPrefix}/scripts/`,
{
method: 'POST',
body: params,
headers: constructHeaders(),
},
okOrErrorCallback
)
}
export async function updateScript(params, scriptID, okOrErrorCallback) {
return request(
`${apiPrefix}/scripts/${scriptID}/`,
{
method: 'PUT',
body: params,
headers: constructHeaders(),
},
okOrErrorCallback
)
}src/utils/request.js
import fetch from 'dva/fetch';
import { notification } from 'antd';
import { routerRedux } from 'dva/router';
import store from '../index';
const codeMessage = {
200: '服务器成功返回请求的数据。',
201: '新建或修改数据成功。',
202: '一个请求已经进入后台排队(异步任务)。',
204: '删除数据成功。',
400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。',
401: '用户没有权限(令牌、用户名、密码错误)。',
403: '用户得到授权,但是访问是被禁止的。',
404: '发出的请求针对的是不存在的记录,服务器没有进行操作。',
406: '请求的格式不可得。',
410: '请求的资源被永久删除,且不会再得到的。',
422: '当创建一个对象时,发生一个验证错误。',
500: '服务器发生错误,请检查服务器。',
502: '网关错误。',
503: '服务不可用,服务器暂时过载或维护。',
504: '网关超时。',
};
function debugResponse(response){
response.json().then(
body => {
console.log(`debugResponse`)
console.log(`typeof body=`, typeof body)
console.log(`body=`, body)
console.log("JSON.stringify(body)=",JSON.stringify(body))
}
)
return response
}
// function noticeErrorInfo(response, respJson, okOrErrorCallback) {
function noticeErrorInfo(response, okOrErrorCallback) {
console.log("noticeErrorInfo: response=", response, ", okOrErrorCallback=", okOrErrorCallback)
console.log(`typeof response=`, typeof response)
console.log("response.status=", response.status)
console.log("response.url=", response.url)
response.json().then(
respJson => {
console.log("response.json().then: respJson=", respJson)
console.log(`typeof respJson=`, typeof respJson)
console.log("JSON.stringify(respJson)=",JSON.stringify(respJson))
let respMessage
if ("message" in respJson) {
respMessage = respJson.message
console.log(`respMessage=`, respMessage)
} else {
console.log("message not in response body")
}
const errorText = respMessage || codeMessage[response.status] || response.statusText
console.log("errorText=", errorText)
notification.error({
message: errorText,
description: `请求 ${response.url} 出错 ${response.status}`,
})
const reqUrlError = new Error(errorText)
reqUrlError.name = response.status
reqUrlError.response = response
console.log("reqUrlError=", reqUrlError)
// throw reqUrlError
// return reqUrlError
if(okOrErrorCallback) {
okOrErrorCallback(reqUrlError)
// console.log("return reqUrlError=", reqUrlError)
// return reqUrlError
}
})
}
/**
* Requests a URL, returning a promise.
*
* @param {string} url The URL we want to request
* @param {object} [options] The options we want to pass to "fetch"
* @return {object} An object containing either "data" or "err"
*/
export default function request(url, options, okOrErrorCallback) {
console.log(`request: url=${url}, options=`, options, ", okOrErrorCallback=", okOrErrorCallback)
const defaultOptions = {
credentials: 'include',
};
const newOptions = { ...defaultOptions, ...options };
if (newOptions.method === 'POST' || newOptions.method === 'PUT' || newOptions.method === 'PATCH') {
if (!(newOptions.body instanceof FormData)) {
newOptions.headers = {
Accept: 'application/json',
'Content-Type': 'application/json; charset=utf-8',
...newOptions.headers,
};
newOptions.body = JSON.stringify(newOptions.body);
} else {
// newOptions.body is FormData
newOptions.headers = {
Accept: 'application/json',
...newOptions.headers,
};
}
}
return fetch(url, newOptions)
// .then(debugResponse)
.then(response => {
console.log("fetch response=", response, ",newOptions=", newOptions)
if (newOptions.method === 'DELETE' || response.status === 204) {
return response.text()
}
if (response.status >= 200 && response.status < 300) {
console.log("ok -> response.status=", response.status)
return response.json()
}
// response.json().then(
// respJson => {
// noticeErrorInfo(response, respJson, okOrErrorCallback)
// }
// )
return noticeErrorInfo(response, okOrErrorCallback)
})
.catch(err => {
console.error(`catch: url=${url} -> error=`, err)
const errorText = `解析请求${url}的返回时出错:${err}`
console.log("errorText=", errorText)
const parseRespError = new Error(errorText)
console.log("parseRespError=", parseRespError)
if(okOrErrorCallback) {
console.log("return parseRespError=", parseRespError)
okOrErrorCallback(parseRespError)
}
// if (okOrErrorCallback) {
// okOrErrorCallback(err)
// } else {
// const { dispatch } = store;
// const status = err.name
// if (status === 401) {
// dispatch({
// type: 'login/logout',
// });
// return;
// }
// if (status === 403) {
// dispatch(routerRedux.push('/exception/403'));
// return;
// }
// if (status <= 504 && status >= 500) {
// dispatch(routerRedux.push('/exception/500'));
// return;
// }
// if (status >= 404 && status < 422) {
// dispatch(routerRedux.push('/exception/404'));
// }
// }
});
}基本上实现了:
如果是出错,则不论是request的url的error,还是response的解析为text或json等的error,都会调用回调函数okOrErrorCallback,然后可以在okOrErrorCallback中写正常和出错的处理的逻辑:
(1)出错情况:
此处去删除本地local storage中token:

模拟没有登录,去调试401没权限的效果是:

以及:
断开localhost的server,模拟网络断开的效果:

(2)正常情况:


转载请注明:在路上 » 【已解决】reactjs的Antd Pro中如何让网络异常出错时也有callback返回可以自己控制异常