Redux is a popular state management library that is widely used in modern web applications. It helps developers to manage the state of the application in a predictable way. TypeScript, on the other hand, is a strongly typed superset of JavaScript that provides better tooling and improved safety. In this tutorial, we will explore how to use Redux with TypeScript to build complex applications.
Prerequisites:
To follow along with this tutorial, you should have a basic understanding of React, Redux, and TypeScript.
Setting Up Redux with TypeScript:
To set up Redux with TypeScript, we need to install the required packages. First, let's install the Redux library and its types using npm:
npm install redux @types/reduxNext, we need to install the React bindings for Redux, which will allow us to use Redux with React:
npm install react-redux @types/react-reduxNow, we can start building our Redux store. The store is the central hub of the application's state. We can create the store using the createStore function from Redux:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const store = createStore(rootReducer, applyMiddleware(thunk));In this example, we are using the applyMiddleware function from Redux to apply the thunk middleware, which allows us to write asynchronous actions in Redux.
Defining Actions and Reducers:
In Redux, actions are plain JavaScript objects that describe what happened in the application. Reducers are pure functions that take the current state and an action, and return a new state.
To define actions and reducers in TypeScript, we need to create interfaces for each action and state shape. Here's an example:
interface Todo {
id: number;
title: string;
completed: boolean;
}
interface TodoState {
todos: Todo[];
}
interface AddTodoAction {
type: 'ADD_TODO';
payload: {
title: string;
};
}
interface ToggleTodoAction {
type: 'TOGGLE_TODO';
payload: {
id: number;
};
}
type TodoAction = AddTodoAction | ToggleTodoAction;
function todosReducer(state: TodoState, action: TodoAction): TodoState {
switch (action.type) {
case 'ADD_TODO':
const newTodo: Todo = {
id: state.todos.length + 1,
title: action.payload.title,
completed: false,
};
return {
...state,
todos: [...state.todos, newTodo],
};
case 'TOGGLE_TODO':
const toggledTodos = state.todos.map((todo) => {
if (todo.id === action.payload.id) {
return {
...todo,
completed: !todo.completed,
};
}
return todo;
});
return {
...state,
todos: toggledTodos,
};
default:
return state;
}
}In this example, we have defined the state shape as an array of todos, and created two actions: AddTodoAction and ToggleTodoAction. We have also defined a TodoAction type that represents the union of these two actions.
The todosReducer function is a pure function that takes the current TodoState and a TodoAction, and returns a new TodoState. The switch statement inside the reducer handles the different actions that can be dispatched.
Connecting Redux with React:
To connect Redux with React, we need to use the Provider component from react-redux. The Provider component is a higher-order component that provides the Redux store to all components in the React tree.
Here's an example of how to use the Provider component:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);In this example, we are wrapping our App component with the Provider component and passing in the store as a prop.
Now, we can use the connect function from react-redux to connect our components to the Redux store. The connect function takes two arguments: mapStateToProps and mapDispatchToProps.
mapStateToProps is a function that maps the Redux state to the props of the component. Here's an example:
interface Props {
todos: Todo[];
addTodo: (title: string) => void;
toggleTodo: (id: number) => void;
}
const mapStateToProps = (state: RootState): Props => ({
todos: state.todos,
});
const mapDispatchToProps = {
addTodo,
toggleTodo,
};
const TodoList: React.FC<Props> = ({ todos, addTodo, toggleTodo }) => {
// ...
};
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
In this example, we are mapping the todos array from the Redux state to the todos prop of the TodoList component. We are also mapping the addTodo and toggleTodo actions to props using the mapDispatchToProps object.
Conclusion:
In this tutorial, we have explored how to use Redux with TypeScript to build complex web applications. We have learned how to define actions and reducers using TypeScript interfaces, and how to connect Redux with React using the Provider component and the connect function. By using TypeScript with Redux, we can create more type-safe and maintainable code.