首页 > 解决方案 > 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;
    }[];
  };
}

回购链接:https ://github.com/danlubbers/arcteryx-graphql

标签: javascriptreactjstypescriptpromiserace-condition

解决方案


这是因为您正在使用空对象初始化产品状态。

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

推荐阅读