Attempt to create React modificable context fails to instantiate provider

Viewed 38

I want to handle auth information as a context in my React app, so I am following this tutorial to implement a context that can be updated from within the components tree. This is my code so far:

app/authContext/index.tsx

import * as React from "react";

export interface IAuth {
  user: string | null;
}
export type AuthContextType = {
  auth: IAuth;
  setAuth: (auth: IAuth) => void;
}

export const auth = {
  user: "username",
}

export const AuthContext = React.createContext<AuthContextType | null>(null);

const AuthContextProvider: React.FC<React.ReactNode> = ({children}) => {
  const [auth, setAuth] = React.useState<IAuth> ({user: null});

  const saveAuth = (auth: IAuth) => {
    setAuth(auth);
  }

  return <AuthContext.Provider value={{auth, saveAuth}}>{children}</AuthContext.Provider>;
}

export default AuthContextProvider;

app/index.tsx

import React from 'react';
import { ThemeProvider } from '@mui/material/styles';
import { Routes, Route } from "react-router-dom";

import './App.css';
import {mayan} from "./themes/mayan";
import AppHeader from './appHeader';

import AuthContextProvider, { auth } from "./authContext";

import Home from "./Routes/home";
import Login from "./Routes/login";

function App() {
  return (
    <ThemeProvider theme={mayan}>
      <AuthContextProvider>    <<<< ---------- Error line
        <div className="App">
          <AppHeader />
          <header className="App-body">
            <Routes>
              <Route path="/" element={<Home />} />
              <Route path="login" element={<Login />} />
            </Routes>
          </header>
        </div>
      </AuthContextProvider>
    </ThemeProvider>
  );
}

export default App;

The problem is that when instantiating a <AuthContextProvider> component, I get the following error:

TS2322: Type '{ children: Element; }' is not assignable to type 'IntrinsicAttributes & ReactNode'.
  Type '{ children: Element; }' is missing the following properties from type 'ReactPortal': key, type, props
    15 |   return (
    16 |     <ThemeProvider theme={mayan}>
  > 17 |       <AuthContextProvider>
       |        ^^^^^^^^^^^^^^^^^^^
    18 |         <div className="App">
    19 |           <AppHeader />
    20 |           <header className="App-body">

I can't tell whether the tutorial is wrong or I'm missing something.

1 Answers

As far as I understand, using React.FC has fallen a bit out of favor. Typescript has been improved to the point it understands what a React component is and what it returns. What it needs to know is what is passed to it. In this case it is just a children prop, so use React.PropsWithChildren<{}>. If you had already other props and a props interface, use React.PropsWithChildren<IProps>.

Example:

export interface IAuth {
  user: string | null;
}

export type AuthContextType = {
  auth: IAuth;
  saveAuth: (auth: IAuth) => void;
};

export const auth = {
  user: "username"
};

export const AuthContext = React.createContext<AuthContextType | null>(null);

const AuthContextProvider = ({
  children
}: React.PropsWithChildren<{}>) => {
  const [auth, setAuth] = React.useState<IAuth>({ user: null });

  const saveAuth = (auth: IAuth) => {
    setAuth(auth);
  };

  return (
    <AuthContext.Provider value={{ auth, saveAuth }}>
      {children}
    </AuthContext.Provider>
  );
};
Related