Home > OS >  Dispatch isn't working in my contextAPI (functional component)
Dispatch isn't working in my contextAPI (functional component)

Time:01-27

I'm working in a simple boolean toggler script but i'm kind noob on typescript and contextapi and can't figure out why do my dispatch don't work.

The context code:


import { createContext, useReducer } from 'react'

const initialState = { openWallet: false };
type AppState = typeof initialState

type ACTIONTYPE =
  | { type: "OPEN_WALLET"; payload: boolean }
  | { type: "CLOSE_WALLET"; payload: boolean };

function reducer(state: AppState, action: ACTIONTYPE) {
  switch (action.type) {
    case "OPEN_WALLET":
      return { openWallet: true };
    case "CLOSE_WALLET":
      return { openWallet: false };
    default:
      return state
  }
}



const AppContext = createContext<{
  state: AppState
  dispatch: React.Dispatch<ACTIONTYPE>;
}>({state: initialState, dispatch: () => {} })

export function AppProvider(props: any) {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <AppContext.Provider value={{ state, dispatch }}>
      {props.children}
    </AppContext.Provider>
  );
}

export { AppContext }

Where i'm calling it:


  const { active } = useWeb3React();

        const { state, dispatch } = useContext(AppContext);
        console.log(state.openWallet)

  return (
    <>

      <StyledNavbar>
      <AccountDiv>{active ? <Account /> : <StyledButton color="secondary" variant="contained" onClick={() => { dispatch({type: 'OPEN_WALLET', payload: true}); console.log(state.openWallet)}}>No wallet connected</StyledButton>}</AccountDiv>     
      </StyledNavbar>
      <Backdrop
        sx={{ color: '#fff', zIndex: (theme) => theme.zIndex.drawer   1 }}
        open={state.openWallet}
        onClick={() => { dispatch({type: 'CLOSE_WALLET', payload: false})}}
      >
        <Wallet />
      </Backdrop>
    </>

Passing it thorugh the app:



function App() {

  const { state, dispatch } = useContext(AppContext);

  return (
    <ThemeProvider theme={theme}>
      <AppContext.Provider value={{state, dispatch}}>
      <Web3ReactProvider getLibrary={getLibrary}>
        <div className="App">
          <img src={logo} alt="logo" width={200} style={{}} />
          <img src={tucano} alt="tucano" width={200} />
          <Header />
          <MediaCard />
        </div>
      </Web3ReactProvider>
      </AppContext.Provider>
    </ThemeProvider>
  );
}

The code is being compiled so i really don't have a single hint. Maybe i'm passing the AppContext wrong?

CodePudding user response:

Ok, first, in your AppContext file you are creating a new context with a default dispatch function of () => {}.

const AppContext = createContext<{
state: AppState
dispatch: React.Dispatch<ACTIONTYPE>;
}>({state: initialState, dispatch: () => {} })

Then, you declare AppProvider and, inside that, you create your real state and dispatch

const [state, dispatch] = useReducer(reducer, initialState);

and pass that into the provider

 <AppContext.Provider value={{ state, dispatch }}>
  {props.children}
</AppContext.Provider>

That is all correct. your issue is that in your App component you arent using any of that. Instead you are creating a new state and dispatch off of the default AppContext as it was initialized and you are passing that into a brand new AppCoontext.Provider

function App() {

  const { state, dispatch } = useContext(AppContext); <-- this is the dispatch you are actually calling and it is defined as () => {}

  return (
<ThemeProvider theme={theme}>
  <AppContext.Provider value={{state, dispatch}}>
  ...
  </AppContext.Provider>
</ThemeProvider>
  );
}

The solution is to just use the AppProvider defined in your AppContext.tsx file

import {AppProvider} from 'somewhere';
function App() {
  return (
<ThemeProvider theme={theme}>
  <AppProvider>
  ...
  </AppProvider>
</ThemeProvider>
  );
}

CodePudding user response:

Bastiat helped me!

The right code where it runs:


function App() {

  const { state, dispatch } = useContext(AppContext);

  return (
    <ThemeProvider theme={theme}>
      <AppProvider>
      <Web3ReactProvider getLibrary={getLibrary}>
        <div className="App">
          <img src={logo} alt="logo" width={200} style={{}} />
          <img src={tucano} alt="tucano" width={200} />
          <Header />
          <MediaCard />
        </div>
      </Web3ReactProvider>
      </AppProvider>
    </ThemeProvider>
  );
}

  •  Tags:  
  • Related