这是避免“提早归还后不小心打了React Hook”的安全方法吗?

时间:2019-05-05 10:22:55

标签: reactjs react-router react-hooks

我写了一个这样的功能组件:

export const SiteMap: React.FunctionComponent = () => {

  return useGetSetData<I.SiteMap>({
    title: "Site Map",
    getData: () => IO.getSiteMap(),
    showData: Page.SiteMap
  });
}

那很好。

顺便说一句,我的useGetSetData是一个“高阶组件”函数,它使用useStateuseEffect来获取数据,然后传递该数据(在获取数据之后)传递给要显示的演示组件。 其参数为:

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”被有条件地调用。在每个组件渲染中,必须以完全相同的顺序调用React Hook。提早归还后,您是否不小心打了个React Hook?反应钩/钩规则

如果我将其重新编码如下,那么它将起作用:

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
  });
}

这是一个微不足道的更改,即,它在功能上等同于我之前编写的代码。

它避免了上面的错误消息,并且似乎可以正常工作。


我的问题是:

  • 我的解决方法是否安全,即此代码是否正确?
  • 否则,在什么情况下可能会失败

1 个答案:

答案 0 :(得分:1)

不安全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}} />;