gpt4 book ai didi

typescript - 如何使用react-query替换context

转载 作者:行者123 更新时间:2023-12-05 08:28:47 24 4
gpt4 key购买 nike

我读了an article on using react-query as a state manager我现在正尝试用 react-query(版本 4)替换我应用程序中的上下文。

之前,我使用 useContext() 创建了一个上下文,它为登录用户存储了一个用户帐户 对象。我使用 react-query 来获取这些数据,然后使用 useReducer() 来修改帐户对象。但是,我意识到这是一团糟,相关数据无论如何都在 react-query 中,所以我应该摆脱上下文和 reducer,直接使用 react-query(我在我进行的查询中生成用户帐户对象 react 查询)。

我在自定义 Hook 中生成用户帐户对象:

function useUser(): UseQueryResult<User, Error> {
const query = getInitialUserUrl;
const platform = usePlatformContext();
return useQuery<User, Error>(
queryKeyUseUser,
async () => {
const data = await fetchAuth(query);
if (didQueryReturnData(data)) {
return new User(platform, data[0]);
}
return new User(platform);
},
{
refetchOnReconnect: 'always',
refetchInterval: false,
},
);
}

export default useUser;

现在我有一个突变,我在其中验证用户的电子邮件地址(使用上下文的旧方法):

const useMutationVerifyEmail = (): UseMutationResult<RpcResponseEmailVerify, Error, FormEmailVerifyInput> => {
const { userObject } = useUserContext();

return useMutation(
(data: FormEmailVerifyInput) => verifyEmail(userObject.id, data.validation_code),
},
);
};

我试图用直接调用 useUser() 来替换对上下文的调用:

const useMutationVerifyEmail = (): UseMutationResult<RpcResponseEmailVerify, Error, FormEmailVerifyInput> => {
const { data: userObject } = useUser();

return useMutation(
(data: FormEmailVerifyInput) => verifyEmail(userObject.id, data.validation_code),
},
);
};

但是,TypeScript 提示 Object is possibly 'undefined' for userObject。我不确定为什么,因为据我所知,useUser() 总是返回一个 User 对象。

如何更新我的自定义 Hook 以返回一个 User 对象,以便我可以使用它而不是上下文?

更新

我可以将我的 useUser() Hook 包裹在另一个 Hook 中:

function useUserObject() {
const { data: userObject } = useUser();
if (userObject instanceof User) {
return userObject;
}
throw new Error('Failed to get account info!');
}

然后我可以执行 const userObject = useUserObject() 来获取用户帐户对象...但这真的是最佳方法吗?我是否需要为自定义 Hook 创建一个自定义 Hook ,以便像使用 useContext() 一样使用我的用户对象?

最佳答案

我写了您在问题中提到的文章。

不能保证 useQuery 在您调用它时返回数据,因为数据还不能获取或者获取可能失败。

现在您可以在您的应用程序中保证这一点,因为您仅在数据已被获取时调用 Hook - 但 TypeScript 不知道这一点。

如文章末尾所述,这是一种权衡。它给你的是每个钩子(Hook)都是独立的。如果您出于某种原因在还没有用户对象的地方调用 useMutationVerifyEmail,它将去尝试获取它。

有多种方法可以“解决/解决”该问题/限制:

  1. 您可以忽略它并使用类型断言/bang 运算符 (!)
const useMutationVerifyEmail = (): UseMutationResult<RpcResponseEmailVerify, Error, FormEmailVerifyInput> => {
const { data: userObject } = useUser();

return useMutation(
(data: FormEmailVerifyInput) => verifyEmail(userObject!.id, data.validation_code),
);
};

如果您将使用此 Hook 的组件移动到用户不可用的地方,这可能会在运行时出错,但如果您知道是这种情况就没关系:)

  1. 可以将mutationFn作为不变量检查在里面,如果没有用户则进行mutation错误:
const useMutationVerifyEmail = (): UseMutationResult<RpcResponseEmailVerify, Error, FormEmailVerifyInput> => {
const { data: userObject } = useUser();

return useMutation(
async (data: FormEmailVerifyInput) => {
if (!userObject) {
throw new Error("no user available")
}
return verifyEmail(userObject.id, data.validation_code)
},
);
};
  1. 您可以将 useUser 调用从您的自定义突变 Hook 中移出,并将 userId 作为传递给突变的输入的一部分。
const useMutationVerifyEmail = (): UseMutationResult<RpcResponseEmailVerify, Error, FormEmailVerifyInput> => {
return useMutation(
({ id, ...data} : FormEmailVerifyInput & { id: number }) => verifyEmail(id, data.validation_code),
);
};

然后,该组件可以调用 useQuery,可能会返回 null,如果没有用户则返回加载微调器或错误,或者您可以禁用触发只要没有用户就可以进行突变。

  1. 您可以后退一步并保留您的上下文,但使用来自 useQuery 的数据填充它:
const UserProvider = ({ children }) => {
const { data } = useUser()

if (data.isLoading) return "loading ..."
if (data.isError) return "error"

return <UserContext.Provider value={data}>{children}</UserContext.Provider>
}

我可能不得不再写一些关于这个模式的内容,因为它不是状态同步/复制。它也使用 React 上下文管理状态。它所做的只是通过 react-context 分发来自 react-query 的数据。 data 保证在您通过 useContext() 读取它时被定义,因此它消除了未定义的检查。

它还会始终为您提供 react-query 的“最新”数据,因为您仍然可以通过 useQuery 订阅 - 就在树的更上层。由于 value 更新,上下文消费者将收到更改通知。

现在也需要权衡取舍,即:

  • 您不能再通过 select 进行部分订阅,因为 react-context 没有选择器。
  • 如果您对多个提供者执行此操作,则有进入瀑布式抓取的风险:抓取用户会“阻塞”应用的其余部分,因为在抓取用户之前它不会呈现 children。这就是为什么在 child 访问它时定义用户(这是需要的),但它也会阻止所有其他会在 child 中发生的提取。

我以前用 EssentialDataProvider 之类的东西做过这件事。它会触发一堆 useQuery 调用,例如我们在应用程序中随处需要的用户和堆栈相关信息 - 因此没有它就无法呈现应用程序。然后我们通过上下文分发它,这样我们就不必在任何地方都对它进行空检查。我们还在服务器上预取这些查询。

这是一个可供您随意使用的好工具,但作为一切,它有利有弊:)

关于typescript - 如何使用react-query替换context,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74667427/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com