javascript - React Typescript Conversion 问题渲染数据
问题描述
这是我的第一篇文章!
我正在使用 graphQL 筛选从 Contentful 获取的产品列表,以查找与用户单击的产品匹配的产品。在我将组件转换为 Typescript 之前,一切正常。我对TS隐约熟悉,几个月前才开始使用它。
当我记录产品时,我用正确的过滤数据返回对象,但是当我访问一个键名“imagesCollection”时,我收到以下 TS 错误消息:
类型“{}”.ts(2339) 上不存在属性“imagesCollection”
如果我// @ts-ignore
的产品图像呈现没有问题。这是某种竞赛条件吗?
非常感谢任何帮助,因为我花了很多时间尝试自己解决它。谢谢!
组件:
const Product = (props: any) => {
// Custom HOOK for fetching Contentful Data
const slug = props.match.params.slug;
const { product } = useContentful(query, slug);
console.log(product);
const [jacketColor, setJacketColor] = useState(null);
const [color, setColor] = useState(null);
useEffect(() => {
setJacketColor(
product.imagesCollection && product.imagesCollection.items[1].url
);
setColor(
// @ts-ignore
product.imagesCollection && product.imagesCollection.items[1].description
);
}, [product]);
const changeColor = (jacketColor: string) => {
// @ts-ignore
const filterHero = product.imagesCollection.items
.filter((heroJacket: { title: string }) =>
heroJacket.title.includes("hero")
)
.filter(
(item: { description: string }) => item.description === jacketColor
);
setJacketColor(filterHero[0].url);
setColor(filterHero[0].description);
};
const thumbnailImages = () => {
return (
// @ts-ignore
product.imagesCollection &&
// @ts-ignore
product.imagesCollection.items
.filter((jacket: queryProps) => jacket.title.includes("thumbnail"))
.map((jacket: { url: string; description: string }, index: number) => {
return (
<img
className={styles.thumbnailImages}
key={`products-${index}`}
src={jacket.url}
// @ts-ignore
alt={product.title}
onClick={() => changeColor(jacket.description)}
/>
);
})
);
};
return (
<>
<Header />
{!product ? (
<Loading />
) : (
<div className={styles.productsContainer}>
{/* @ts-ignore */}
<p className={styles.title}>{product && product.title}</p>
{documentToReactComponents(
// @ts-ignore
product.description && product.description.json,
RICHTEXT_OPTIONS
)}
{/* @ts-ignore */}
<p className={styles.price}>{`$${product && product.price}`}</p>
{
<img
className={styles.productImage}
// @ts-ignore
src={jacketColor}
// @ts-ignore
alt={product && product.title}
/>
}
<p className={styles.selectColor}>{`Select a colour: ${color}`}</p>
<div className={styles.thumbnailImagesWrapper}>
{thumbnailImages()}
</div>
</div>
)}
</>
);
};
export default Product;
获取数据的自定义钩子:
function useContentful(query: string, slug: string | null) {
const [products, setProducts] = useState([]);
const [product, setProduct] = useState({});
useEffect(() => {
fetch(graphqlURL, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${REACT_APP_CDA_TOKEN}`,
},
body: JSON.stringify({ query }),
})
.then((res) => res.json())
.then(({ data }) => {
if (slug) {
data.arcteryxCollection.items.filter((item: queryProps) => {
return item.slug === slug && setProduct(item);
});
} else {
setProducts(data.arcteryxCollection.items);
}
})
.catch((err) => console.error(err));
}, [query, slug]);
return { product, products };
}
graphQL 查询结构:
export const query = `
query {
arcteryxCollection {
items {
title
slug
description {
json
}
price
imagesCollection {
items {
url
title
description
}
}
}
}
}
`;
我正在导入的 TS 接口:
export interface queryProps {
title: string;
slug: string;
price: number;
description: {
json: {
content: {
value: string;
}[];
};
};
imagesCollection: {
items: {
url: string;
title: string;
description: string;
}[];
};
}
解决方案
这是因为您正在使用空对象初始化产品状态。
const [product, setProduct] = useState({});
这使得 TypeScript 推断出你的状态类型是一个空对象。因此,它没有一个imagesCollection
。
您可以给它一个类型或使用具有所需属性的对象对其进行初始化。
这是为您的产品添加类型的示例。您可以从 Graph QL 响应中添加需要使用的其他属性。
type ImageCollectionItem = {
url: string;
title: string;
description: string;
}
type ProductState = {
imagesCollection?: {
items: ImageCollectionItem[]
}
}
//...
const [product, setProduct] = useState<ProductState>({});