It's been more than a year since React introduced hooks. Many popular libraries that used ReactJS like React-Router, React-Redux, Material UI, etc. now support hooks and functional components and their type definition. But Today in this article, I will show you the new way of accessing redux store and dispatch in your functional component with strictly typed code in typescript without using any higher-order components, and compare how the redux hooks useDispatch and useSelector reduced a huge pile of boilerplate code.
So to use redux hooks in react using typescript's strictly type definition, you just have to import useDispatch and useSelector. You don't need to provide explicit dispatch type and useSelector takes two types, one is complete store type and the other is the state you want to pick from the store. You can define it as type IStateProps = Pick<TReduxStore, "user">;
to define the second type of argument.
Check the below examples of both functional and class components and later detailed use of both hooks useDispatch and useSelector.
Related Article: Latest Features of Typescript 2020 Release
React Redux hooks: Class vs Functional Components
I will take an example in typescript and show you how the store state access and redux action dispatch work differently in class-based and functional components and what their differences will be.
(See the complete code on Code Sandbox)
I'm writing a simple class component and a functional component that renders the name of a user. First, we dispatch the user's name, and next, we select the name from the redux store in the component to display it in the element.
import * as React from "react";
import { connect } from "react-redux";
import { TReduxStore, TDispatch } from "./types";
import { AxiosPromise } from "axios";
import { getUser } from "./action";
type IStateProps = Pick<TReduxStore, "user">;
interface IDispatchProps {
getUser: (id: string) => AxiosPromise;
}
interface IProps extends IStateProps, IDispatchProps {}
class ShowUser extends React.Component<IProps> {
componentDidMount() {
this.props.getUser("1");
}
render() {
const { user } = this.props;
return !user ? "Loading..." : <div>User Name: {user.name}</div>;
}
}
const mapStateToProps = (state: TReduxStore): IStateProps => ({
user: state.user
});
const mapDispatchToProps = (dispatch: TDispatch): IDispatchProps => ({
getUser: id => dispatch(getUser(id))
});
export default connect(
mapStateToProps,
mapDispatchToProps
)(ShowUser);
Above is the traditional way of connecting your ReactJS component with the redux. You must write that much code to request and display the user name. Now let's see the same thing in the functional component with typescript.
import * as React from "react";
import { useSelector, useDispatch } from "react-redux";
import { TReduxStore, TDispatch } from "./types";
import { getUser } from "./action";
type IStateProps = Pick<TReduxStore, "user">;
const ShowUser: React.FC = props => {
const dispatch = useDispatch<TDispatch>();
const { user } = useSelector<TReduxStore, IStateProps>(state => ({
user: state.user
}));
React.useEffect(() => {
dispatch(getUser("1"));
}, [dispatch]);
return !user ? <div>"Loading..."</div> : <div>User Name: {user.name}</div>;
};
export default ShowUser;
As you can see, using useSelector and useDispatch hooks, the number of lines was reduced to almost half. I'm considering you're using the class component, so I'm not explaining that snippet. So I'm just explaining the FunctionalComponent.tsx below.
Use useDispatch and useSelector react-redux hooks in your functional component.
Let's see one by one how to use the useDispatch and the useSelector to dispatch and select the data from the redux store with typescript
-
useDispatch
useDispatch hook used to get the redux dispatch function in your functional component or hook. It takes a generic type of data dispatch and takes in its parameters. Usually, it is
{type: string, payload?: any}
but as I'm redux-thunk here, so its type isThunkDispatch<TReduxStore, {}, TAction>;
whereTReduxStore
is the type of the store andTAction
is{type: string, payload?: any}
. -
useSelector
As its name suggests, it gives you the functionality of selecting the data from your redux store. It takes one parameter, which is a callback, where it passes the whole redux state, and you return the data you want to select from it. So the callback function looks like below.
function (state) { return ({ user: state.user }) }
The same thing I have written is in the flat arrow function format in the typescript functional component. It takes two types in its generic type. One is the type of your redux store, and the second is the type you want to select from the store. In my codes, it is represented by
TReduxStore
andIStateProps
respectively.