【问题标题】:Object is possibly null in TypeScript ReactTypeScript React 中的对象可能为空
【发布时间】:2019-11-10 02:09:07
【问题描述】:

使用此代码:

const Products = () => {
  const classes = useStyles();

  const { data } = useFetch('/categories');

  return (
    <div className={classes.root}>
      <GridList cellHeight={180} className={classes.gridList}>
        <GridListTile key="Subheader" cols={6} style={{ height: 'auto' }} />
        {data &&
          data.map((category: CategoryInterface) => {
            return (
              <GridListTile key={category.id}>
                <GridListTileBar title={category.name} />
              </GridListTile>
            );
          })}
      </GridList>
    </div>
  );
};

我在地图之前的数据上得到“对象可能为空”,我尝试使用 && 运算符来摆脱它,我还尝试定义像 const categories = data as CategoryInterface[] 这样的变量,但这表明我必须先转换为未知,我应该怎么做呢?

这里是 useFetch 钩子

import { useEffect, useState } from 'react';

export const useFetch = (url: string) => {
  const [state, setState] = useState({ data: null, loading: true });

  useEffect(() => {
    setState(state => ({ data: state.data, loading: true }));

    fetch(url)
      .then(res => res.json())
      .then(json => setState({ data: json, loading: false }));
  }, [url, setState]);

  return state;
};

【问题讨论】:

  • 您的数据是什么样的?是数组吗?
  • 我添加了代码,它的类型为 null

标签: reactjs typescript


【解决方案1】:

你的useFetch 钩子应该是这样的:

import { useEffect, useState } from 'react';

export const useFetch = (url: string) => {
  const [state, setState] = useState({ data: {}, loading: true }); //Don't assign null to state variable

  useEffect(() => {
    setState(state => ({ data: state.data, loading: true })); //Remove this line, this is not needed 

    fetch(url)
      .then(res => res.json())
      .then(json => setState({ data: json, loading: false }));
  }, [url, setState]); //Replace [url, setState] with [] as your second argument to make useEffect work for first time.

  return state;
};

你的用法应该是:

const { data } = useFetch('/categories');

{data.length>0 &&
  data.map((category: CategoryInterface) => {
    return (
      <GridListTile key={category.id}>
        <GridListTileBar title={category.name} />
      </GridListTile>
    );
  })
}

【讨论】:

    【解决方案2】:

    Typescript 将类型分配给 JavaScript 变量。大多数情况下,当您使用 TS 时,您应该在使用前定义变量类型。但是,如果可能,TS 有时可以推断出变量的类型。

    您似乎将 JS 代码复制粘贴到 TypeScript 中并试图使其工作。所以首先我建议为你要使用的变量定义类型,这样 TS 会设置正确的类型。

    useState 的初始调用使state.data 的类型为null(这是唯一TS 知道它的类型)。与 JS 不同,TS 不允许在执行期间更改类型。所以state.data在程序执行期间会有null类型。

    const [state, setState] = useState({ data: null, loading: true });
    // Type of state is
    // { data: null, loading: boolean }
    

    要更正此问题,您应该提前提供state 变量的类型。它的一个可能值是null。另一个可能的值 - 是从fetch 接收的数据。您可能应该知道从fetch 返回的数据的 JSON 类型是什么,所以请输入它。

    从你的代码我可以猜到,该数据类型可能看起来像这样

    type IData = CategoryInterface[];
    

    CategoryInterface 可能看起来像

    interface CategoryInterface {
        id: string;
        name: string; 
    }
    

    所以IData 将是state.data 的第二种可能类型。所以在useState调用期间分配state的类型

    const [state, setState] = useState<{data: IData | null, loading: boolean}>({ data: null, loading: true });
    

    但您应该保留 {data &amp;&amp; data.map (/*...*/)},因为在数据完全加载之前,state.data 将是未定义的。

    完整代码

    interface CategoryInterface {
        id: string;
        name: string;
    }
    
    type IData = CategoryInterface[];
    
    export const useFetch = (url: string) => {
        const [state, setState] = useState<{ data: IData | null, loading: boolean }>({ data: null, loading: true });
    
        useEffect(() => {
            setState(state => ({ data: state.data, loading: true }));
    
            fetch(url)
                .then(res => res.json())
                .then(json => setState({ data: json, loading: false }));
        }, [url, setState]);
    
        return state;
    };
    

    【讨论】:

    • 谢谢,确实是JS项目的
    猜你喜欢
    • 2019-10-22
    • 1970-01-01
    • 2022-01-01
    • 1970-01-01
    • 2022-01-14
    • 1970-01-01
    • 2021-12-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多