3

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.

3
  • Wouldn't dialogContext?.setDialogOpen work? Commented May 25, 2020 at 7:34
  • meaning to use dialogContext ? dialogContext.setDialogOpen : null; ??? hm it is not working. Commented May 25, 2020 at 7:38
  • i have updated my question the way DialogContext is defined. Commented May 25, 2020 at 7:50

3 Answers 3

1

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


import * as React from "react";
import { Route, Switch, BrowserRouter as Router } from "react-router-dom";

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

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

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

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

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

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

export default function MainComponent() {
  const [showDialog, setShowDialog] = React.useState(false);

  return (
    <DialogContext.Provider
      value={{
        setShowDialog
      }}
    >
      {showDialog && <Dialog />}
      <Router>
        <Switch>
          <Route path="/">
            <Home />
          </Route>
          <Route path="/books">
            <Books />
          </Route>
        </Switch>
      </Router>
    </DialogContext.Provider>
  );
}

Sign up to request clarification or add additional context in comments.

4 Comments

After removing ? character for the setDialogOpen meaning removing it from being optional then gives me an error "argument of type {} is not assignable to parameter of type 'ContextProps'. Property setDialogOpen is missing in type {} but required in ContextProps.
i get this in this line export const DialogContext = React.createContext<ContextProps>({}); and also this error in the question still exists
seems like i have to pass some default value in this line export const DialogContext = React.createContext<ContextProps>({}); not sure what that could be
I've edited the code , you can play around with it here on code sandbox: codesandbox.io/s/great-dew-7zml2?file=/src/App.tsx:107-1782
1

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);

Comments

0

The issue is you are saying setDialogOpen is optional in ContextProps when you provide the ?. This error will go away if you always require setDialogOpen (remove the ? from your interface definition)

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

Alternatively you can call setDialogOpen conditionally

setDialogOpen?.(true)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.