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