Issue
I have a src/reducers/index.tsx
file where I output all my reducers:
import counterReducer from '../reducers/counter';
import loggedReducer from '../reducers/isLogged';
import {combineReducers} from 'redux';
const allReducers = combineReducers({
counter: counterReducer,
isLogged: loggedReducer,
});
export default allReducers;
Then in my src/index.tsx
:
import {Provider} from 'react-redux';
const store = createStore(allReducers);
ReactDOM.render(
<React.Fragment>
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root'),
);
And finally in my src/app.tsx
I have:
import {useSelector} from 'react-redux';
const App = () => {
const counter = useSelector(state => state.counter);
return (
<h1>counter {counter}</h1>
);
};
The error is reported in the state.counter
part of the useSelector
:
> Property 'counter' does not exist on type 'DefaultRootState'.ts(2339)
It looks like the store is never actually created?
Solution
Non-hacky answer inbound!
Shortest Answer:
Link to Redux Toolkit docs for creating typed react-redux hooks: https://react-redux.js.org/using-react-redux/usage-with-typescript#define-root-state-and-dispatch-types
(While this is a link to the Redux Toolkit docs, I believe this technique should still work with "vanilla" react-redux
. Please someone correct me with a comment if I'm wrong.)
Short Answer:
The useSelector
hook by itself is unaware of the typing that should be applied to the state you want to use. You'll have to do a couple lines of work to earn your type safety! Utilizing the technique shown in the link, you'll get to have the typings for your state every time you use it. You'll create a one-line custom hook that utilizes the native useSelector
hook with the inferred types from your root state to find out what your states' types are supposed to be.
Longer Answer:
The useSelector
hook by itself is unaware of the typing that should be applied to the state you want to use. To make it so that the types of your store get captured and applied to your useSelector
hooks, you'll need to jump through two small hoops. We're also going to take care of your useDispatch
hook while we're at it.
Step 1
Let's grab the inferred types from the store. To do this, we'll go to where our store is created and use some Typescript magic to get the inferred types from the state:
// Copied from Redux Toolkit docs that are linked above
// store.ts
import rootReducer from './rootReducer'
const store = createStore(rootReducer)
export type RootState = ReturnType<typeof store.getState>
export type AppDispatch = typeof store.dispatch
Brief pause to unpack lines 6 and 7:
Line 6: export type RootState = ReturnType<typeof store.getState>
ReturnType
means "The return type of the function."typeof
means "Tell me what the types are of this thing."store.getState
is a function that returns the state object that is currently in the store.
Now put those pieces together!: Whatever is being returned from store.getState, I want the types stored as the RootState
variable!
Line 7: export type AppDispatch = typeof store.dispatch
typeof
means "Tell me what the types are of this thing."store.dispatch
means "I want the dispatch object used to dispatch actions to the store."
Now put those pieces together!: Get the dispatch object from the store, break it down into it's types, and store it in the AppDispatch
variable!
Step 2
Now that we have the inferred types from our store and dispatch, we can apply them to our hooks. We will do this by creating a custom hook so that we don't have to handle typing our hooks every time we go to use them:
// Copied from Redux Toolkit docs that are linked above
// hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux'
import type { RootState, AppDispatch } from './store'
// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = () => useDispatch<AppDispatch>()
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
Here, we are taking the types that we created in store.ts
and applying them to the useDispatch
and useSelector
hooks that we normally use in react-redux
. From now on, you'll have your types set up for you when you use your new custom hooks!
Voila! You now have type safety in your react-redux hook implementation!
Answered By - Anthony Shew
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.