这是避免 "Did you accidentally call a React Hook after an early return?" 的安全方法吗
Is this a safe way to avoid "Did you accidentally call a React Hook after an early return?"
我写了这样一个函数组件:
export const SiteMap: React.FunctionComponent = () => {
return useGetSetData<I.SiteMap>({
title: "Site Map",
getData: () => IO.getSiteMap(),
showData: Page.SiteMap
});
}
效果不错。
顺便说一句,我的 useGetSetData
是一个 "high order component" 函数,它使用 useState
和 useEffect
来获取数据,然后传递该数据(在它fetched) 传递给要显示的传入表示组件。
它的参数是:
interface UseGetDataPropsT<T> {
title: string,
getData: () => Promise<T>,
showData: (data: T) => ReactElement
}
无论如何,下次我尝试使用一个页面,其内容取决于 URL 中的一些其他内容,我的代码如下:
type RouterProps = ReactRouter.RouteComponentProps<any>;
export const Image: React.FunctionComponent<RouterProps> = (props: RouterProps) => {
const imageId: number | undefined = getId(props, "Image");
if (!imageId) {
return NoMatch(props);
return useGetSetData<I.Image>({
title: "Image",
getData: () => IO.getImage(imageId),
showData: Page.Image
});
}
这会产生一条错误消息:
React Hook "useGetSetData" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return? react-hooks/rules-of-hooks
如果我按如下方式重新编码,那么它就可以工作了:
export const Image: React.FunctionComponent<RouterProps> = (props: RouterProps) => {
const imageId: number | undefined = getId(props, "Image");
if (!imageId) {
return NoMatch(props);
return ImageId(imageId);
}
export const ImageId: React.FunctionComponent<number> = (imageId: number) => {
return useGetSetData<I.Image>({
title: "Image",
getData: () => IO.getImage(imageId),
showData: Page.Image
});
}
这是一个微不足道的变化,即它在功能上等同于我之前编写的代码。
它避免了上面的错误消息,并且似乎可以正常运行。
我的问题是:
- 我的变通方法安全吗,即这段代码是否正确?
- 如果不是那么在什么情况下会失败
不安全,react-hooks/rules-of-hooks
只是一个 eslint rule 不够聪明(还)没有意识到你被骗了
问题与之前完全相同,在https://overreacted.io/why-do-hooks-rely-on-call-order/
中有解释
解决方案是有条件地渲染一个单独的组件(无条件地调用钩子)=> 使用 JSX 的 React.createElement(ImageId...)
而不是调用普通函数:
if (!imageId) {
return <NoMatch {...props} />};
}
return <ImageId {...{imageId}} />;
我写了这样一个函数组件:
export const SiteMap: React.FunctionComponent = () => {
return useGetSetData<I.SiteMap>({
title: "Site Map",
getData: () => IO.getSiteMap(),
showData: Page.SiteMap
});
}
效果不错。
顺便说一句,我的 useGetSetData
是一个 "high order component" 函数,它使用 useState
和 useEffect
来获取数据,然后传递该数据(在它fetched) 传递给要显示的传入表示组件。
它的参数是:
interface UseGetDataPropsT<T> {
title: string,
getData: () => Promise<T>,
showData: (data: T) => ReactElement
}
无论如何,下次我尝试使用一个页面,其内容取决于 URL 中的一些其他内容,我的代码如下:
type RouterProps = ReactRouter.RouteComponentProps<any>;
export const Image: React.FunctionComponent<RouterProps> = (props: RouterProps) => {
const imageId: number | undefined = getId(props, "Image");
if (!imageId) {
return NoMatch(props);
return useGetSetData<I.Image>({
title: "Image",
getData: () => IO.getImage(imageId),
showData: Page.Image
});
}
这会产生一条错误消息:
React Hook "useGetSetData" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return? react-hooks/rules-of-hooks
如果我按如下方式重新编码,那么它就可以工作了:
export const Image: React.FunctionComponent<RouterProps> = (props: RouterProps) => {
const imageId: number | undefined = getId(props, "Image");
if (!imageId) {
return NoMatch(props);
return ImageId(imageId);
}
export const ImageId: React.FunctionComponent<number> = (imageId: number) => {
return useGetSetData<I.Image>({
title: "Image",
getData: () => IO.getImage(imageId),
showData: Page.Image
});
}
这是一个微不足道的变化,即它在功能上等同于我之前编写的代码。
它避免了上面的错误消息,并且似乎可以正常运行。
我的问题是:
- 我的变通方法安全吗,即这段代码是否正确?
- 如果不是那么在什么情况下会失败
不安全,react-hooks/rules-of-hooks
只是一个 eslint rule 不够聪明(还)没有意识到你被骗了
问题与之前完全相同,在https://overreacted.io/why-do-hooks-rely-on-call-order/
中有解释解决方案是有条件地渲染一个单独的组件(无条件地调用钩子)=> 使用 JSX 的 React.createElement(ImageId...)
而不是调用普通函数:
if (!imageId) {
return <NoMatch {...props} />};
}
return <ImageId {...{imageId}} />;