React-Redux Hooks With Typescript is going to be a continued version of our previous blog, React Hooks with Typescript. So if you are new to hooks, we would suggest looking into that article first, which talks about setting up the starter kit of React hooks with typescript and AntD for UI components.

If you know the basics of React hooks, like useEffect or useState, you can even give it a skip.

Since React push using of functional components, a lot of libraries around react start publishing their own hooks, Redux being one of them, as almost most React projects use Redux these days.

The Redux hooks APIs provide an alternative to connect HOC and go away with mapStateToProps, and mapDispatchToProps, and I must say these hooks API provide a much cleaner way of doing that.

Now without going much in theory, let’s deep dive into the coding part.

Create a new component file src/components/ReduxHooksComponent.tsx, if not already with 2 input fields and a submit button

Create A Normal Functional Component


import React, {ChangeEvent, FormEvent, useState, useEffect} from "react";
import {Form, Input, Button} from "antd";

interface Props {
}

const ReduxHooksComponent: React.FC<Props> = () => {


    return (
        <Form layout="inline">
            <Form.Item>
                <Input type="text" placeholder="name"/>
                <Input type="text" placeholder="address" />
                <Button htmlType="submit" type="primary"> Submit </Button>
            </Form.Item>
        </Form>
    )
};

export default ReduxHooksComponent;

Now import this component in App.tsx


import React from 'react';
import './App.css';
import ReduxHooksComponent from "./components/ReduxHooksComponent";

const App: React.FC = () => {
  return (
    <div className="App">
      <ReduxHooksComponent/>
    </div>
  );
};

export default App;

Pretty Simple. Right! after running the code it should render a component with 2 input and a submit button.

Setting up the store, actions, and reducers.

Firstly add redux and react-redux to the project


yarn add react-redux @types/react-redux redux

Create two files, src/store/index.ts and src/store/root-reducer.ts

let’s start creating each and every component of the root reducer, which would be actions, states, reducers

# src/store/root-reducer.ts

import {Action, Reducer} from "redux";

export interface InitialState {
    name: string;
    address: string;
}

export const initialState: InitialState = {
    name: '',
    address: '',
};

export interface DispatchAction extends Action {
    payload: Partial<InitialState>;
}

export const rootReducer: Reducer<InitialState, DispatchAction> = (state, action) => {
    return initialState;
};


Now we have a simple reducer that does nothing but returns the initial state.

Read More:   Update Optimizing Data Queries for Time Series Applications

Let’s create a store using this rootReducer, so our src/store/index.ts will look like


import {DispatchAction, InitialState, rootReducer} from "./root-reducer";
import {createStore} from "redux";


export const store = createStore<InitialState, DispatchAction, null, null>(rootReducer);

Also, updating the index.tsx file to wrap App with Provider and provide the store to the provider.

# src/index.tsx

........
ReactDOM.render(<Provider store={store}><App /></Provider>, document.getElementById('root'));
........

That’s all, well you won’t see any visible changes on the browser, but eventually, you have integrated a redux into your react code.

Now let’s create some actions. Update the root-reducer.ts so that it should look something like

# src/store/root-reducer.ts

.......
export interface DispatchAction extends Action<ActionType> {
    payload: Partial<InitialState>;
}

export enum ActionType {
    UpdateName,
    UpdateAddress,
    DeleteName,
    DeleteAddress,
}

export const rootReducer: Reducer<InitialState, DispatchAction> = (state = initialState, action) => {
    if (action.type === ActionType.UpdateName) {
        return {...state, name: action.payload.name || ''};
    } else if (action.type === ActionType.DeleteName) {
        return {...state, name: ''};
    } else if (action.type === ActionType.DeleteAddress) {
        return {...state, address: ''};
    } else if (action.type === ActionType.UpdateAddress) {
        return {...state, name: action.payload.name || ''};
    } else return state;
};

Pretty Simple, Yes! We have just returned an updated version of the state with new values as per the actions suggest.

Lets create a Dispatcher too in the same file

src/store/root-redux.ts

.......
export class RootDispatcher {
    
    private readonly dispatch: Dispatch<DispatchAction>;
    
    constructor(dispatch: Dispatch<DispatchAction>){
        this.dispatch = dispatch; 
    }
    updateName = (name: string) => this.dispatch({type: ActionType.UpdateName, payload: {name}});
    
    updateAddress = (address: string) => this.dispatch({type: ActionType.UpdateAddress, payload: {address}});
    
    deleteName = () => this.dispatch({type: ActionType.DeleteName, payload: {}});
    
    deleteAddress = () => this.dispatch({type: ActionType.DeleteAddress, payload: {}})
}
......

Well, now we are done with all the dispatchers, actions, stores. basically our entire redux is set up. Now all we need to do is dispatch actions from components and use values from the store.

Using Dispatcher and Store in Components via Hooks

Redux hooks provide 2 main hooks, useSelector and useDispatch

useSelector give access to the entire store object, and we can select only what we are interested in

useDispatch give access to dispatch, which will be used to create the Dispatcher object of RootDispatcher and then dispatch events to update state.

Read More:   Technology Decisions for a Successful Observability Strategy – InApps Technology 2022

Let’s create an interface of all the property we are interested in accessing from the store,


interface StateProps {
    name: string;
    address: string;
}

UseSelector to assign name and address state


    const {name, address} = useSelector<InitialState, StateProps>((state: InitialState) => {
        return {
            name: state.name,
            address: state.address
        }
    });

Now useDispatch to get a dispatch object and create a new instance of RootDispatcher


const dispatch = useDispatch();
const rootDispatcher = new RootDispatcher(dispatch);

After integrating both state and dispatcher from to the component our file will look something like

#src/components/ReduxHooksComponent.tsx

import React, {ChangeEvent, FormEvent, useState, useEffect} from "react";
import {Form, Input, Button} from "antd";
import {useDispatch, useSelector} from "react-redux";
import {InitialState, RootDispatcher} from "../store/root-reducer";

interface Props {
}

interface StateProps {
    name: string;
    address: string;
}

const ReduxHooksComponent: React.FC<Props> = () => {

    const {name, address} = useSelector<InitialState, StateProps>((state: InitialState) => {
        return {
            name: state.name,
            address: state.address
        }
    });

    const dispatch = useDispatch();
    const rootDispatcher = new RootDispatcher(dispatch);


    return (
        <Form layout="inline">
            <Form.Item>
                <Input type="text" placeholder="name" value={name}
                       onChange={(e: ChangeEvent<HTMLInputElement>) => {
                           rootDispatcher.updateName(e.target.value)}
                       }
                />
                <Input type="text" placeholder="address" value={address}
                       onChange={(e: ChangeEvent<HTMLInputElement>) =>{
                           rootDispatcher.updateAddress(e.target.value)}
                       }
                />
                <Button htmlType="submit" type="primary"> Submit </Button>
            </Form.Item>
        </Form>
    )
};

export default ReduxHooksComponent;

NOTE: The selector is approximately equivalent to the mapStateToProps argument to connect conceptually. The selector will be called with the entire Redux store state as its only argument. The selector will be run whenever the function component renders. useSelector() will also subscribe to the Redux store, and run your selector whenever an action is dispatched.

useSelector() uses strict === reference equality checks by default, not shallow equality, to use shallow Equality, we can use shallowEqual from react-redux

so our selector code would look something like


    const {name, address} = useSelector<InitialState, StateProps>((state: InitialState) => {
        return {
            name: state.name,
            address: state.address
        }
    }, shallowEqual);

To Sum Up

We hope that we can help you more to deep dive into the world of React-Redux Hooks and that you will be able to apply everything you have learned here to practical use. This article is written by the InApps editorial team.

Read More:   Observable CI/CD Pipelines for DevOps Success – InApps Technology 2022

InApps Technology is one of the top IT outsourcing companies in the world, consult our experts if you want to outsource your software projects for better prices and successful projects.

FAQs

1. Should I use TypeScript with React Redux?

We strongly recommend using TypeScript in Redux applications. However, like all tools, TypeScript has tradeoffs. It adds complexity in terms of writing additional code, understanding TS syntax, and building the application.

2. Can I use TypeScript with React? 

TypeScript is now very good for React if you use hooks with it.

3. Is TypeScript good for React?

Over the past few years, TypeScript has gained immense popularity among front-end developers. Improved maintainability, code consistency, and future browser support are a few reasons behind its success

4. Is redux still relevant in 2022?

Modern Redux is still very useful in large applications, so yes, it is still relevant. Speaking of which, no React state management library list would be complete without Redux.

Rate this post
As a Senior Tech Enthusiast, I bring a decade of experience to the realm of tech writing, blending deep industry knowledge with a passion for storytelling. With expertise in software development to emerging tech trends like AI and IoT—my articles not only inform but also inspire. My journey in tech writing has been marked by a commitment to accuracy, clarity, and engaging storytelling, making me a trusted voice in the tech community.

Let’s create the next big thing together!

Coming together is a beginning. Keeping together is progress. Working together is success.

Let’s talk

Get a custom Proposal

Please fill in your information and your need to get a suitable solution.

    You need to enter your email to download

      [cf7sr-simple-recaptcha]

      Success. Downloading...