[英]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.