Javascript 承诺解析函数返回未定义的

Javascript 承诺解析函数返回未定义的,javascript,reactjs,async-await,state,fetch-api,Javascript,Reactjs,Async Await,State,Fetch Api,我为我想要使用的API编写了一个util包装器。包装器处理请求构建和令牌获取 从“./refreshToken”导入refreshToken /** * Fetch util handles errors, tokens and request building for the wrapped API calls * @param {string} url Request URL e.g. /chargehistory * @param {string} requestMethod Req

我为我想要使用的API编写了一个util包装器。包装器处理请求构建和令牌获取

从“./refreshToken”导入refreshToken

/**
 * Fetch util handles errors, tokens and request building for the wrapped API calls
 * @param {string} url Request URL e.g. /chargehistory
 * @param {string} requestMethod Request Method [GET, POST, PUT, DELETE]
 * @param {object} requestBody Request Body as JSON object
 * @param {object} retryFn The caller function as object reference to retry
 * @private This function is only used as util in this class
 * @async
 */
const fetchUtil = (url, requestMethod, requestBody, retryFn) => {
    // Block thread if the token needs to be refetched
    if(sessionStorage.getItem('token') == null || Number(sessionStorage.getItem('token_expiration')) < new Date().getTime()) {
        refreshToken()
    }        

    let request = {
        method: requestMethod,
        headers: {
            'Authorization': `Bearer ${sessionStorage.getItem('token')}`,
            'Content-Type': 'application/json'
        }
    }
    if(requestMethod === 'POST' || requestMethod === 'PUT') {
        request.body = JSON.stringify(requestBody)
    }

    fetch(`${process.env.REACT_APP_API}${url}`, request)
    .then(response => {
        if(response.ok) {
            return response.json()
        } else if(response.status === 401) {
            refreshToken().then(() => retryFn())
        } else {
            console.error(`Error on fetching data from API: ${response.status}, ${response.text}`)
        }
    })
    .then(json => {
        console.log(json)
        return json
    })
    .catch(error => console.error(error))
}
打印未定义的
,虽然我确实期望函数引用或承诺,但我多少能理解这一点。
我尝试在fetchUtil和调用者之前添加
async
,并
wait
fetchUtil。这给了我一个错误,没有调用undefined上的wait。我还试着把它重新编织成一个根本不起作用的钩子。
我需要组件的
useffect
挂钩中的数据:

const Cockpit = () => {
    const { t } = useTranslation()
    const [chargehistory, setChargehistory] = useState(undefined)
    const [installationreport, setInstallationreport] = useState(undefined)

    useEffect(() => {
        setChargehistory(getChargehistory)
        setInstallationreport(getInstallationreport)
    }, [])
}

为什么我得到了未定义的
以及如何解决这个问题?

fetchUtil
函数中,它以没有返回值结束,这意味着
fetchUtil
函数将隐式返回
未定义的

你说

fetch(`${process.env.REACT_APP_API}${url}`, request)
    .then(response => {
        if(response.ok) {
            return response.json()
        } else if(response.status === 401) {
            refreshToken().then(() => retryFn())
        } else {
            console.error(`Error on fetching data from API: ${response.status}, ${response.text}`)
        }
    })
    .then(json => {
        console.log(json) // (1) 
        return json
    })
    .catch(error => console.error(error))
在这个函数中,
(1)
部分工作正常,对吗

我想如果你像下面这样修改你的代码,它会工作的

首先,像这样更新
fetchUtil
代码。回传

const fetchUtil = (url, requestMethod, requestBody, retryFn) => {
    // Block thread if the token needs to be refetched
    if(sessionStorage.getItem('token') == null || Number(sessionStorage.getItem('token_expiration')) < new Date().getTime()) {
        refreshToken()
    }        

    let request = {
        method: requestMethod,
        headers: {
            'Authorization': `Bearer ${sessionStorage.getItem('token')}`,
            'Content-Type': 'application/json'
        }
    }
    if(requestMethod === 'POST' || requestMethod === 'PUT') {
        request.body = JSON.stringify(requestBody)
    }

    // return fetch here! it will return a promise object. 
    return fetch(`${process.env.REACT_APP_API}${url}`, request)
    .then(response => {
        if(response.ok) {
            return response.json()
        } else if(response.status === 401) {
            refreshToken().then(() => retryFn())
        } else {
            console.error(`Error on fetching data from API: ${response.status}, ${response.text}`)
        }
    })
    .then(json => {
        console.log(json)
        return json
    })
    .catch(error => console.error(error))
}

因为我不能完全访问您的代码,所以可能仍然会有错误,但我希望这会有所帮助

fetchUtil
函数中,在
fetch
之前需要一个return关键字:
return fetch(…)
。还请注意,您应该在
fetchUtil
函数中处理错误,或者抛出错误以允许调用代码捕获并处理错误。个人我将从
fetchUtil
函数中删除
catch
方法调用,并在调用
fetchUtil
函数的任何地方链接一个
catch
方法。另一个解决方案是添加一个简单的回调函数作为参数并调用它,而不是返回承诺的最后一个
函数确实解决了getChargehistory(installationId)中的问题,但它没有解决在useEffect()之后组件树中现在有一个挂起的结果的问题。您的意思是
setChargehistory(getChargehistory)
part不起作用吗?如果是,这是因为
getChargehistory
本身将promise对象返回为挂起状态。我认为如果你想用
setChargehistory
设置结果,你必须在
getChargehistory
函数中进行设置。这可能会有帮助!
const fetchUtil = (url, requestMethod, requestBody, retryFn) => {
    // Block thread if the token needs to be refetched
    if(sessionStorage.getItem('token') == null || Number(sessionStorage.getItem('token_expiration')) < new Date().getTime()) {
        refreshToken()
    }        

    let request = {
        method: requestMethod,
        headers: {
            'Authorization': `Bearer ${sessionStorage.getItem('token')}`,
            'Content-Type': 'application/json'
        }
    }
    if(requestMethod === 'POST' || requestMethod === 'PUT') {
        request.body = JSON.stringify(requestBody)
    }

    // return fetch here! it will return a promise object. 
    return fetch(`${process.env.REACT_APP_API}${url}`, request)
    .then(response => {
        if(response.ok) {
            return response.json()
        } else if(response.status === 401) {
            refreshToken().then(() => retryFn())
        } else {
            console.error(`Error on fetching data from API: ${response.status}, ${response.text}`)
        }
    })
    .then(json => {
        console.log(json)
        return json
    })
    .catch(error => console.error(error))
}
const getChargehistory = async (installationId) => {
    const result =  await fetchUtil(`/chargehistory?options.installationId=${installationId}`, 'GET', {}, getChargehistory)
    console.log(result);
}