簡體   English   中英

使用 Typescript 和 React Hooks 反應 HOC

[英]React HOC with Typescript and React Hooks

我正在嘗試在我的 HOC 中使用 React Hooks 將一個事件傳遞給父級,該事件表示該組件何時位於 Viewport 上,以使用React Intersection Observer延遲加載此組件數據,但我正在努力解決以下錯誤: Type '(props: IStockProps) => JSX.Element | JSX.Element[]' is not assignable to type 'FC<IStockProps>'. Type '(props: IStockProps) => JSX.Element | JSX.Element[]' is not assignable to type 'FC<IStockProps>'.

我最近開始使用 Typescript,但我仍在學習如何閱讀這些錯誤,有時可能會有些混亂。 這是我的代碼

高鐵

import React, { useEffect, ComponentType, Component } from "react";
import { useInView } from "react-intersection-observer";

interface IHocProps {
  [key: string]: any;
}


export const LazyLoader = (WrappedComponent: ComponentType<IHocProps>) =>
  function Comp(props: IHocProps) {
    const { onEnterView } = props;
    const [ref, inView] = useInView({
      triggerOnce: true,
    });
    useEffect(() => {
      inView && onEnterView();
    }, [inView]);
    return <WrappedComponent ref={ref} {...props} />;
  };

成分:

import React from "react";
import { Skeleton, Space } from "antd";

interface IStockProps {
  isLoading: boolean;
  stockSituation: object;
}

export const StockSituation: React.FC<IStockProps> = (props: IStockProps) => {
  const { isLoading, stockSituation } = props;
  const renderSkeleton = (
    <>
      <Skeleton paragraph={{ rows: 2 }} active={true} />
      <Space
        style={{ justifyContent: "center" }}
        direction="horizontal"
        align="center"
        size="large"
      >
        <Skeleton.Avatar size={200} active={true} />
        <Skeleton.Avatar size={200} active={true} />
        <Skeleton.Avatar size={200} active={true} />
        <Skeleton.Avatar size={200} active={true} />
      </Space>
    </>
  );
  return isLoading
    ? renderSkeleton
    : Object.keys(stockSituation).map((stock) => (
        <p>{stockSituation[stock as keyof IStockProps["stockSituation"]]}</p>
      ));
};

儀表盤

import React from "react";
import { useSelector, useDispatch } from "react-redux";
import { RootState } from "@store";
import {getStock, IStock} from "@store/dashboard/dashboard";
import { Grid, Row, Col } from "react-flexbox-grid";
import {LazyLoader} from "@components";


  const stock: IStock = useSelector(
    ({ dashboard: { stock } }: RootState) => stock
  );
  const loadInfo = () => {
    console.log("info");
    dispatch(getStock());
  };

  const LazyStockSituation = LazyLoader(StockSituation);

  return (
    <>
      <Header />
      <Grid>
          <Row>
            <Col>
                <LazyStockSituation
                  onEnterView={loadInfo}
                  stockSituation={stock}
                  isLoading={!stock}
                />
              </Panel>
            </Col>
          </Row>
      </Grid>
    </>
  );
};

編輯:所以,我發現這個錯誤是由組件而不是 HOC 引起的,所以我修復了它,但現在我收到了新的錯誤,更可怕

Argument of type 'FC<IStockProps>' is not assignable to parameter of type 'ComponentType<IHocProps>'.

Type 'FunctionComponent<IStockProps>' is not assignable to type 'FunctionComponent<IHocProps>'.

Types of parameters 'props' and 'props' are incompatible.

 Type 'PropsWithChildren<IHocProps>' is not assignable to type 'PropsWithChildren<IStockProps>'.

Type 'PropsWithChildren<IHocProps>' is missing the following properties from type 'IStockProps': isLoading, stockSituation

所有這些錯誤都是大約試圖通過props與接口IHocProps到接收組件props與接口IStockProps ,對不對? 有沒有辦法讓我的 HOC 接收更通用的可能類型,以便我可以將它與任何其他組件一起使用?

好吧,Typescript 編譯器實際上是在告訴您出了什么問題,但是在您剛開始使用 Typescript 時看不到它是可以理解的。

問題出在你的組件上,你現在返回,JSX 元素 | JSXElement[] 正如編譯器所說。 React.FC 必須返回有效的“React Element”。 如果你改變這個:

  return isLoading
    ? renderSkeleton
    : Object.keys(stockSituation).map((stock) => (
        <p>{stockSituation[stock as keyof IStockProps["stockSituation"]]}</p>
      ));

到:

return  (
    <>
    {
        isLoading ?
        renderSkeleton : Object.keys(stockSituation).map((stock) => (
            <p>{stockSituation[stock as keyof IStockProps["stockSituation"]]}</p>
          ))
    }
  </>
)

您的代碼應該可以工作。 關鍵是在 React.Fragment 中包裝 return

但是,如果我可以問,為什么要使用 HOC,尤其是使用鈎子? 鈎子的要點是不使用 HOC。

你可以用鈎子做到這一點,將邏輯提取到鈎子中

const useLazyLoader = (onEnterView: () => void) => {
    const [ref, inView] = useInView({
      triggerOnce: true,
    });
    useEffect(() => {
      inView && onEnterView();
    }, [inView]);
    return ref
}

並在您的組件中使用它

const onEnterView = () => {} // whatever you want
const lazyStockedRef = useLazyLoader(onEnterView)
return <StockSituation ref={lazyStockedRef} /* other props here */ />

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM