user3204268
user3204268

Reputation: 21

React, Typescript, Hooks. Cannot invoke an expression whose type lacks a call signature

I am new to react hooks and fairly new to typescript. I have been trying to make use of hooks, specifically the useContext hook, to manage global state (I appreciate for this example it may be overkill, but my goal is just to be able to understand it really). I have followed a few different examples, but none using typescript and am now getting this error:

Cannot invoke an expression whose type lacks a call signature. Type 'ContextProps' has no compatible call signatures.

I've looked at multiple other questions on here which explain the solution (something about the union on the signatures), but I just can't get my head around it in relation to my code.

This is a simplified version on my code (please excuse, as I'm still learning :) ), but I get the error on the handleOpenDrawer function in MainPage.tsx:

App.tsx

import React, { createContext, Dispatch, useReducer } from 'react';
import MainPage from './MainPage';

interface ContextProps {
    drawerState: DrawerState;
    drawerDispatch: Dispatch<DrawerActions>;
}

interface DrawerState {
    open: boolean;
}

const initialDrawerPosition:DrawerState = {
    open: false,
};

interface DrawerActions {
    type: 'OPEN_DRAWER' | 'CLOSE_DRAWER';
}

const reducer = (state:DrawerState, action:DrawerActions) => {
    switch (action.type) {
        case 'OPEN_DRAWER':
            return {
                ...state,
                open: true,
            };
        case 'CLOSE_DRAWER':
            return {
                ...state,
                open: false,
            };
        default:
            return state;
    }
};

export const DrawerDispatch = createContext({} as ContextProps);

export default function App() {
    const [ drawerState, drawerDispatch ] = useReducer(reducer, initialDrawerPosition);

    const value = { drawerState, drawerDispatch };

    return (
        <DrawerDispatch.Provider value={value}>
            <MainPage />
        </DrawerDispatch.Provider>
    );

}

MainPage.tsx

import { useContext } from 'react';
import { DrawerDispatch } from './App';

export default function App() {
    const dispatch = useContext(DrawerDispatch);

    const handleOpenDrawer = () => {
        dispatch({ type: 'OPEN_DRAWER' });
    };

    return (
        <button onClick={handleOpenDrawer}>
            Click me
        </button>
    );
}

I'm expecting to be able to update the state.open to true using the dispatch, but instead get the error mentioned above. Any help would be massively appreciated!

Upvotes: 0

Views: 1267

Answers (1)

user3204268
user3204268

Reputation: 21

I figured it out, so thought I better put it on here in case anyone else is having the same issue.
useContext(DrawerDispatch) returns an object and dispatch is one of the properties on that object, so const dispatch needs destructuring:
const { dispatch } = useContext(DrawerDispatch) will do it.
or better variable naming:
const context = useContext(DrawerDispatch) and then call it like context.dispatch instead of just dispatch.

Upvotes: 2

Related Questions