【问题标题】:Data in useRequest function is potentially null/undefined - Typescript, ReactuseRequest 函数中的数据可能为 null/未定义 - Typescript、React
【发布时间】:2022-01-20 07:55:32
【问题描述】:

我们制作了一个自定义挂钩来为我们获取数据。获取部分被我们生成的获取 API 替换,我们作为参数传递下来。

interface RequestModel<T> {
  loading: boolean;
  error: string | null;
  data: T | null;
}

export default function useRequest<T>(url: string): [boolean, string | null, T | null, Dispatch<SetStateAction<RequestModel<T>>>] {

  const [data, setData] = useState<RequestModel<T>>({
    loading: false,
    error: null,
    data: null
  });

  useEffect(() => {
    setData({
      loading: true,
      error: null,
      data: null
    });

    fetch(url)
      .then((response) => response.json())
      .then((json) =>
        setData({
          loading: false,
          error: null,
          data: json
        })
      )
      .catch((error) => {
        setData({
          loading: false,
          error: error.message,
          data: null
        });
      });
  }, [url]);

  return [data.loading, data.error, data.data, setData];
}

它的用法是这样的:

const [loading, error, data, setData] = useRequest<Todo>(url);

现在当我们调用 setData 时出现的问题是 prevState 可能是null(例如请求失败并且从未设置数据)。所以像这样调用 setData 会导致错误:

function handleChange(event: ChangeEvent<HTMLInputElement>) {
    setData((prevState) => ({
      ...prevState,
      data: {
        ...prevState.data,
        [event.target.name]: event.target.title
      }
    }));
  }

将使用 prevState 的 setData 包装在 if (data) {} 中不起作用。我想这是因为 setState 是异步的,并且在调用 setData 时数据可能会更改为 null(因此它的属性未定义)。

问题 1 关于如何使这个 useRequest 挂钩起作用的任何建议?理想情况下,我希望能够使用数据,而不必在每次使用时都检查 null 或 undefined(对于上述情况,这是不可能的)。

问题 2 我还认为可以使用默认状态初始化数据并使用默认状态而不是将数据设置为null。有没有办法根据 Typescript 中的接口/类型生成默认对象?类似于 Java,其中变量具有默认值。

Codesandbox

【问题讨论】:

    标签: reactjs typescript types


    【解决方案1】:

    我建议如果 loading === true 时不能调用 handleChange 以避免发出多个并行请求(例如,您可以通过禁用更改按钮来做到这一点)。

    另外,你有没有尝试过类似的方法但没有成功?

    function handleChange(event: ChangeEvent<HTMLInputElement>) {
        setData((prevState) => ({
          ...prevState,
          data: prevState.data ? {
            ...prevState.data,
            [event.target.name]: event.target.title
          } : null
        }));
      }
    

    关于你的第二个问题,如果发生错误,我认为你不应该将data 分配给默认值,因为它不清楚。在我看来,在这种情况下使用null 是更好的解决方案。

    【讨论】:

    • 我忘记添加代码框链接,现在添加。实际上,我已经构建了一个只有在!loading 时才能调用handleChange 的结构。没想到检查prevState.data。我将不得不尝试并考虑一下。谢谢!
    • 实际上,当您检查 prevState.data 而不是尝试在 else 部分分配 [event.target.name]: event.target.value 时,它应该只是 null。否则它将无法正常工作。
    猜你喜欢
    • 2018-02-02
    • 2020-05-11
    • 1970-01-01
    • 1970-01-01
    • 2017-01-20
    • 2015-04-09
    • 2018-03-15
    • 2020-08-11
    • 1970-01-01
    相关资源
    最近更新 更多