2
votes

i want to fix the error "cannot invoke an object which can possibly be undefined" using react and typescript.

what i am trying to do? I am using usecontext react hook and creating a variable from it (dialogContext) in the components (home, Dialog and books component). In doing so i get the above mentioned error.

I am defining DialogContext in helper file like below

interface ContextProps {
    setDialogOpen?: (open: boolean) => void;   
}

export const DialogContext = React.createContext<ContextProps>({});

And importing DialogContext in components where needed that is (Main, home, Dialog components)

function MainComponent() {
  let [showDialog, setShowDialog] = React.useState(false);
  return (
      <DialogContext.Provider
          value={{
              setDialogOpen: (open: boolean) => {
                  if (open) {
                      const sessionDialogClosed = sessionStorage.getItem('dialog');
                      if (sessionDialogClosed !== 'closed') {
                          setShowDialog(open);
                          sessionStorage.setItem('dialog', 'closed');
                      }
                  } else {
                      setShowDialog(open);
                  }
              },
          }}
      >
      {showDialog && <Dialog DialogContext={DialogContext}/>
          <Route 
              path="/items">
              <Home />
          </Route>
          <Route
              path="/id/item_id">
              <Books/>
          </Route>
      </DialogContext.Provider>
  )     
}


function Home() {
    const dialogContext= React.useContext(DialogContext);
    const handleClick = () {
        dialogContext.setDialogOpen(true); //get error here
    }
    return ( 
        <button onClick={handleClick}>add</button>
    )
}


function Books({DialogContext} : Props) {
    const dialogContext= React.useContext(DialogContext);
    const handleClick = () {
        dialogContext.setDialogOpen(true); //get error here
    }
    return ( 
        <button onClick={handleClick()}>Click me</button>
    )    
}

function Dialog() {
    return(
        <div>
            //sometext
           <button onClick={dialogContext.setDialogOpen(false)}> hide</button> //get errror here
        </div>
   ) 

}

What i have tried?

I have added a check for undefined where dialogContext is used in components (Books, Home, Dialog) like for example in Books components i used like below,

function Books({DialogContext} : Props) {
    const dialogContext= React.useContext(DialogContext);
    const handleClick = () {
        if (dialogContext !== 'undefined') {
            dialogContext.setDialogOpen(true); //get error here
        }
    }
    return ( 
        <button onClick={handleClick()}>Click me</button>
    )    
}

But still the error "cannot invoke an object which can possibly be undefined" throws.

Could someone help me fix this error. thanks.

Edit:

I have tried to do below and it removes the error

function Books({DialogContext} : Props) {
    const dialogContext= React.useContext(DialogContext);
    const handleClick = () {
        if (dialogContext && dialogContext.setDialogOpen) {
            dialogContext.setDialogOpen(true); 
        }
    }
    return ( 
        <button onClick={handleClick()}>Click me</button>
    )    
}

But instead of adding a check like this in every component what change should i make in the DialogContext helper file or what needs to be changed to fix keep checking for undefined or not. thanks.

2
Wouldn't dialogContext?.setDialogOpen work? - Baruch
meaning to use dialogContext ? dialogContext.setDialogOpen : null; ??? hm it is not working. - someuser2491
i have updated my question the way DialogContext is defined. - someuser2491

2 Answers

0
votes

You have a lot of typing mistakes in your code , I've edited the answer based on your comments and here is the final result. you can also see how it's work in codesandbox just click here to see.

and here is All of your code + a some fixes + a little change in structure


interface ContextProps {
  setDialogOpen: (open: boolean) => void;
}

const DialogContext = React.createContext<ContextProps>({
  setDialogOpen: (open: boolean) => {}
});

function Home() {
  const dialogContext = React.useContext(DialogContext);
  const handleClick = () => {
    dialogContext.setDialogOpen(true); //It's Ok
  };

  return <button onClick={handleClick}>add</button>;
}

function Books() {
  const dialogContext = React.useContext(DialogContext);
  const handleClick = () => {
    dialogContext.setDialogOpen(true); //get error here
  };
  return <button onClick={handleClick}>Click me</button>;
}

function Dialog() {
  const dialogContext = React.useContext(DialogContext);
  const handleClick = () => {
    dialogContext.setDialogOpen(false);
  };
  return (
    <div>
      <button onClick={handleClick}> hide</button>
    </div>
  );
}

export default function MainComponent() {
  const [showDialog, setShowDialog] = React.useState(false);
  console.log("hi");
  const setDialogOpen = (open: boolean) => {
    if (open) {
      // const sessionDialogClosed = sessionStorage.getItem("dialog");
      // if (sessionDialogClosed !== "closed") {
      setShowDialog(open);
      //   sessionStorage.setItem("dialog", "closed");
      // }
    } else {
      setShowDialog(open);
    }
  };
  return (
    <DialogContext.Provider
      value={{
        setDialogOpen
      }}
    >
      {showDialog && <Dialog />}
      <Router>
        <Switch>
          <Route path="/">
            <Home />
          </Route>
          <Route path="/books">
            <Books />
          </Route>
        </Switch>
      </Router>
    </DialogContext.Provider>
  );
}
0
votes

There's no sense in providing a default value for the context. It's redundant boilerplate, especially when it's complex.

Just fake the type:

const DialogContext = createContext(null as any as ContextProps);