首页 > 解决方案 > 同步加载 React Provider 组件的模式

问题描述

我的 :brain: 正在爆炸。

在我的应用程序的根目录中,我想设置一个 UserProvider(下面的简化版本)。

我希望它的所有消费者都相信 Provider 拥有用户。

通过以下实现,我需要对每次使用进行空检查:

  const userContext = useContext(UserContext)
  const userId = userContext!.id   // I do not want that bang(!)

我目前的实现:

interface IUserContext {
  id: string
  email: string
}

const UserContext = React.createContext<IUserContext|null>(null);

const UserProvider: React.FC = ({ children }) => {
  const [user, setUser] = useState(initalContext);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    client
      .query<CurrentUserQuery>({
        query: currentUserQuery
      })
      .then((res) => {
        if (res.error) {
          logger(res.error);
        }
        if (res.data.me) {
          setUser(res.data.me);
          setLoading(false);
        }
      });
  });

  if (loading) {
    return <Loading />;
  }

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

我知道我可以做类似的事情:

const emptyUser = {
  id: '',
  email: ''
}

const UserContext = React.createContext(emptyUser);

但这对我来说真的很难闻。

有没有人想出一个干净的解决方案?

谢谢!

标签: reactjstypescriptapollo-clientreact-hooksreact-context

解决方案


您声明您的上下文接受 aIUserContextnull,这就是您需要 bang! 的原因。

从上下文中解包 a 的解决方案是User如果用户是抛出异常null(无论如何都不应该发生这种情况?)。然后 Typescript 会推断出您的用户实际上不是 null 而是实际的User

const userContext = createContext<User | null>(null)

const useUser = (): User => {
  const user = useContext(userContext)

  if (user === null) {
    throw new Error('You forgot the provider')
  }

  return user // This is a User
}

推荐阅读