使用async/await在useEffect内的try-catch块中未定义数据,但在切换到Promises时有效



所以我有这样的代码:

useEffect(async () => {
if (someData) {
try {
console.log('inside try block', someData) // undefined
const response = await get(apiUrl('urlInObject') + `${someData}`, {
someData,
})
const { returnedData: someData, someOtherReturnedData } = response
setDataInSessionStore({
someData,
someOtherReturnedData,
})
showNotification({
type: 'success',
message: `The operation was successful.`,
})
router.push('/pages/other-page')
} catch (error) {
if (error.code === 400) {
showNotification({ message: `${error.data}` })
}
if (error.code === 404) {
showNotification({
message: `'${someData}' is not valid. Please try again.`,
})
router.push('/pages/different-page')
}
console.error('ERROR: ', error)
}
}, [])

从store.js导入的setDataInSessionStore的源,使用带有persistent:的zustand

import create from 'zustand'
import { devtools, persist } from 'zustand/middleware'
// items in here don't expire on hard refresh
export const useSession = create(
devtools(
persist(
(set, get) => ({
dataInSessionStore: {},
setDataInSessionStore: (dataInSessionStore) => set({ dataInSessionStore }),
}),
{
name: 'my-session', // unique name
getStorage: () => sessionStorage,
}
)
)
)

showNotification组件内部:

import React from 'react' 
let ref
export function showNotification (notification) {
ref && ref.setState({ ...ref.state, ...notification, open: true })
}
export class Notification extends React.Component {
constructor (props) {
super(props)
this.state = { open: false, message: null, type: 'error', length: 3000 }
}
componentDidUpdate () {
if (this.state.message) {
this.timeout && clearTimeout(this.timeout)
this.timeout = setTimeout(
() => this.timeout && this.setState({ open: false }),
this.state.length
)
}
}
componentWillUnmount () {
this.timeout && clearTimeout(this.timeout)
}
render () {
const { open, message, type } = this.state
if (!ref) ref = this
if (!message) return null
return (
<div className={`notification-bar ${type} ${open ? 'bar-open' : 'bar-closed'}`}>
<span className='text'>
{message}
</span>
<div className='close-icon' />
</div>
)
}
}
export default Notification

下面是使用Promises的代码示例:

useEffect(() => {
if (someData) {
setLoading(true)
get(apiUrl('someUrl') + `${someData}`, {
someData,
})
.then((response) => {
const { data: someData, someOtherData } = response
setDataInSessionStore({
someData,
someOtherData,
})
showNotification({
type: 'success',
message: `The operation was successful.`,
})
router.push('/pages/other-page')
})
.catch((error) => {
if (error.code === 400) {
showNotification({ message: `${error.data}` })
}
if (error.code === 404) {
showNotification({
message: `'${someData}' is not valid. Please try again.`,
})
router.push('/pages/different-page')
}
console.error('ERROR: ', error)
})
}
}, [])

我记录了try块外的数据,数据存在,但try块内的数据未定义。如果我将代码切换为使用Promises而不是异步等待+尝试捕获,则数据存在。我正在使用NextJS,并使用带有persistent的zustand存储来将数据设置到会话存储。

您应该将someData附加到useEffect的第二个参数的数组中,因为someData是局部状态之一,您的副作用取决于someData

这是我创建的CSB。

useEffect(() => {
const someFunction = async () => {
if (!someData) return
try {
console.log(someData) // someData is undefined
// make an API request with the data and do something
} catch (error) {
console.error('ERROR: ', error)
}
}
someFunction()
}, [someData])

您是想在该组件中查询动态页面的数据,还是想查询带有最终在动态页面中呈现的道具的JSX.Element(如[slug].js(?

如果上面的情况是真的,那么你只需要在router.query的末尾加上方括号内调用的动态页面

例如,对于文件pages/services/[slug].tsx,我调用以下内容:

const router = useRouter();
const slug = router.query.slug as string;

你可能想知道为什么我在router.query.slug之后断言as string;这样做的原因是因为CCD_ 9解析为CCD_。由于它不是一个包罗万象的路由,所以我只想要一个解析的slug字符串值。

也就是说,router.query本身是具有以下类型定义的ParsedUrlQuery类型:

interface ParsedUrlQuery extends NodeJS.Dict<string | string[]> {}

您可能想知道有条件未定义的值来自哪里,因为到目前为止,它在这些定义中都不明显。NodeJS.Dict中的字典是条件未定义的根所在的位置:

interface Dict<T> {
[key: string]: T | undefined;
}

这就是你在试块中获得undefined的最终方式

为了对其进行分解,node_modules/next/dist/next-server/lib/router/router.d.ts中有一个名为interpolateAs的函数,其定义如下:

export declare function interpolateAs(route: string, asPathname: string, query: ParsedUrlQuery): {
params: string[];
result: string;
};

它正在为route查找[name].js或[name].tsx;必须将此名称附加到已解析的url查询(router.query.name(中,才能正确解析数据。

最新更新