reactjs 如何更好地键入React Context,以假定该值将始终被定义,而不必为'createContext'给予默认值

2vuwiymt  于 2022-11-04  发布在  React
关注(0)|答案(2)|浏览(97)

我的应用程序中有一个AuthProvider,如果用户未登录,它将自动重定向到登录页面

interface IAuthContext {
  token: string | undefined;
}

export const AuthContext = createContext<IAuthContext>({ token: undefined });

export const AuthProvider = ({ children }: { children: ReactNode }) => {
  const [token, setToken] = useState<string | undefined>();
  const navigate = useNavigate();
  useEffect(() => {
    const authToken = localStorage.getItem('authToken');

    if (!authToken) {
      navigate('/login');
    }
    setToken(token);
  }, []);

  return <AuthContext.Provider value={{ token }}>{children}</AuthContext.Provider>;
};

MyCompAuthProvider的子项。因此,应始终定义token,因为如果它不存在,则AuthProvider将重定向到登录页面,并且永远不会呈现MyComp

export const MyComp = () => {
  const { token } = useContext(AuthContext);

  if (!token) {
    throw new Error('missing token');
  }

  const data = useMemo(() => fetchData(token), token);

  return <div>{data}</div>;
};

每次使用token时,都要Assert它不是未定义的,这很烦人。
有没有更好的方法来输入它,这样我就不需要Assert令牌已经定义,也不需要给予createContext一个默认值?

zwghvu4y

zwghvu4y1#

interface IAuthContext {
  token: string;
}

export const AuthContext = createContext<IAuthContext>({ token: '' });

export const AuthProvider = ({ children }: { children: ReactNode }) => {
  const [token, setToken] = useState('');
  const navigate = useNavigate();

  useEffect(() => {
    const authToken = localStorage.getItem('authToken');

    if (!authToken) {
      navigate('/login');
    } else {
      setToken(authToken);
    }
  }, [token]);

  if (!token) return null;

  return <AuthContext.Provider value={{ token }}>{children}</AuthContext.Provider>;
};
zrfyljdw

zrfyljdw2#

找到了一种使用typescript函数重载和自定义react钩子的方法

interface IAuthContext {
  token: string;
}

const AuthContext = createContext<IAuthContext | undefined>(undefined);

export function useAuthContext(acceptUndefined: true): IAuthContext | undefined;
export function useAuthContext(): IAuthContext;
export function useAuthContext(acceptUndefined?: true) {
  const authContext = useContext(AuthContext);
  if (!authContext && !acceptUndefined) {
    throw 'The component is not a child of AuthProvider';
  }
  return authContext;
}

然后,我可以使用useAuthContext钩子来获取一个定义的上下文。

const MyComp = () => {
  const { token } = useAuthContext();

  const data = useMemo(() => fetchData(token), token);

  return <div>{data}</div>;
};

如果我想自己处理默认上下文值,我也可以将true传递给useAuthContext

const MyComp = () => {
  const authContext = useAuthContext(true);
  if (!authContext) {
    throw 'AuthContext undefined';
  }
  const { token } = authContext;
  // ... //
};

相关问题