Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

reactjs - 'AuthProvider' cannot be used as a JSX component

I attempt to make auth flow in Context Provider and have troubles with TypeScript. Here is problem fragment of Provider code:

interface AuthUserProviderProps {
  children?: React.ReactNode 
}

interface AuthUserInterface {
  token: string;
  setToken: (value: string) => void;
  loggedIn: boolean;
  };
  setBrand: (value: {}) => void;
}

export const authUser = createContext<AuthUserInterface | null >(null);

const AuthUserProvider = ({ children }: AuthUserProviderProps) => {

if (accessTokenVAR() && !jwtToken?.roles.toString().includes('admin')) {
  return isBrowser ? window.location.replace('www.somewhere.com') : ''
}

  return (
    <authUser.Provider
      value={{
        token,
        setToken,
        loggedIn,
      }}
    >
      { children}
    </authUser.Provider>
  );
};

export default AuthUserProvider;

App.tsx

export default function App({ Component, pageProps }: AppProps) {
  const apolloClient = useApollo(pageProps.initialApolloState);
  return (
    <ThemeProvider theme={TifTheme}>
      <AuthUserProvider>                      <===This line throws error
        <ApolloProvider client={apolloClient} >
          <CssBaseline />
          <Component {...pageProps} />
        </ApolloProvider>
      </AuthUserProvider>
    </ThemeProvider>
  );
}

The error is 'AuthUserProvider' cannot be used as a JSX component. Its return type 'void | "" | Element' is not a valid JSX element. Type 'void' is not assignable to type 'Element.' and it is caused by return redirect. But I have no clue how to handle this error

question from:https://stackoverflow.com/questions/65853551/authprovider-cannot-be-used-as-a-jsx-component

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Your analysis should be correct, it's the return of the "redirect". You can easily type properties of React functional components with React.FunctionComponent.

I would recommend to write a little useAccess hook and use that to get a boolean for display reasons or redirect the user with a useEffect. As you redirect to a different page, it shouldn't matter what the component returns. So I modified your code to this, I made some changes and added comments, let me know if it helps.

import { createContext, FunctionComponent, useEffect, useMemo } from "react";

interface AuthUserInterface {
  token: string;
  setToken: (value: string) => void;
  loggedIn: boolean;
  setBrand: (value: any) => void;
}

const AuthUser = createContext<AuthUserInterface | null>(null);

const useAccess = (isBrowser: boolean) => {
  const hasAccess = useMemo(
    () => accessTokenVAR() && !jwtToken?.roles.toString().includes("admin"),
    // TODO: check if that's correct, these variables were not in your answer,
    // might need to add/pass them to the hook
    [accessTokenVAR, jwtToken]
  );

  useEffect(() => {
    // redirect here if has
    if (hasAccess && isBrowser) window.location.replace("www.somewhere.com");
  }, [isBrowser, hasAccess]);

  return hasAccess;
};

interface AuthUserProviderProps {
  isBrowser: boolean;
}

const AuthUserProvider: FunctionComponent<AuthUserProviderProps> = ({
  children,
  isBrowser
}) => {
  const hasAccess = useAccess(isBrowser);

  return (
    <>
      {!hasAccess && <p>"No access"</p>}
      {hasAccess && (
        <AuthUser.Provider
          value={{
            // TODO: values not in question, where do they come from
            token,
            setToken,
            loggedIn
          }}
        >
          {children}
        </AuthUser.Provider>
      )}
    </>
  );
};

export { AuthUserProvider as default, AuthUser };

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...