Это безопасный способ избежать "Ты случайно позвонил в React Hook после раннего возвращения?" - PullRequest
3 голосов
/ 05 мая 2019

Я написал такой компонент функции:

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

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

Это отлично работает.

Кстати, моя useGetSetData - это функция "компонента высокого порядка", которая использует useState и useEffect для выборки данных и которая затем передает эти данные (после их выборки) в переданную презентацию компонент, который будет показан. Его параметры:

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 Hooks должны вызываться в том же порядке в каждом компоненте рендера. Вы случайно позвонили в 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 Ответ

1 голос
/ 05 мая 2019

небезопасно , react-hooks/rules-of-hooks - это просто правило отбора , которое недостаточно умно (пока), чтобы понять, что вас обманули

проблема точно такая же , как и раньше, объясненная в https://overreacted.io/why-do-hooks-rely-on-call-order/

Решение

будет состоять в том, чтобы условно отобразить отдельный компонент (который безоговорочно вызвал бы ловушку) => использовать React.createElement(ImageId...) JSX вместо вызова простой функции:

  if (!imageId) {
    return <NoMatch {...props} />};
  }

  return <ImageId {...{imageId}} />;
...