Fly High with React and Redux: Building a Flight Booking App — Chapter 2

Al Amin Alif
6 min readMar 18, 2023

--

Welcome to chapter — 2 of the Redux and React journey. In the first chapter we wrote an application in vanilla js to dispatch an action to reducer and update our state. In this article, we’ll explore how to use React and Redux together to build a flight booking application.

Prerequisites: Before we start, make sure you have the following tools installed on your computer:

  • Node.js
  • NPM or Yarn
  • Vite
  • Redux
Flight Booking using React & Redux

Step 1: Setting Up the React App with Vite We’ll start by creating a new React app using Vite. Open your terminal and type the following command: npm init @vitejs/app flight-booking-app --template react Once the installation is complete, navigate into the new project directory by running cd flight-booking-app

Note that Vite is a build tool that offers a faster development experience compared to Create React App, as it uses an optimized development server that provides hot module replacement (HMR) out of the box. It also supports a wide range of modern web technologies and allows for easy customization of the project configuration.

Step 2: Installing Redux To use Redux in our application, we need to install two packages: redux and react-redux. Open your terminal and run the following command: npm install redux react-redux

Step 3: In the src directory, create a new folder called redux. Inside this folder, create another folder called booking. This folder will contain the Redux code for managing the booking feature of the application.

Inside the booking folder, create three new files: actions.js, actionTypes.js, and reducer.js.

The actionTypes.js file will contain the constants that define the action types for booking-related actions. For example:

// This is actionTypes.js file
export const ADD_BOOKING = 'ADD_BOOKING';
export const DELETE_BOOKING = 'DELETE_BOOKING';

The actions.js file will contain action creators for booking-related actions. These action creators will create and dispatch actions to the Redux store. For example:

// This is actions.js file
import { ADD_BOOKING, DELETE_BOOKING } from './actionTypes';
//bringing the constants from action types.js

export const addBooking = (booking) => {
return {
type: ADD_BOOKING,
payload: booking
};
};

export const deleteBooking = (bookingId) => {
return {
type: DELETE_BOOKING,
payload: bookingId
};
};

The bookingReducer.js file will contain the reducer function for managing the state of bookings. For example:

//Our bookingReducer.js file
import { ADD_BOOKING, DELETE_BOOKING } from './actionTypes';

const initialState = [];

const bookingReducer = (state = initialState, action) => {
switch (action.type) {
case ADD_BOOKING:
let booking = action.payload;
return [...state, booking];
case DELETE_BOOKING:
let bookingId = action.payload;
return state.filter((el) => el.id !== bookingId);
default:
return state;
}
};
export default bookingReducer;

In this code block, we have defined a Redux reducer function called bookingReducer that takes two arguments: state and action.

The reducer function is responsible for updating the application state based on the action dispatched by the components. It checks the action.type to determine what type of action was dispatched, and then returns a new state object that reflects the change caused by the action.

In this case, we have defined two action types: ADD_BOOKING and DELETE_BOOKING. If the action type is ADD_BOOKING, the reducer adds a new booking object to the state array by creating a new array with the spread operator and appending the new booking object to the end.

If the action type is DELETE_BOOKING, the reducer filters out the booking object with the matching id from the state array using the filter method, which returns a new array that excludes the deleted booking object.

The use of the spread operator and the filter method ensures that the state is updated immutably, meaning that the original state is not mutated or modified directly. Instead, a new state object is created and returned by the reducer function.

Here’s a simplified diagram of how the initial state is updated:

+---------------+
| Component |
+---------------+
|
v
+----------------+
| dispatch() |
+----------------+
|
v
+-----------------+ +-----------------+
| Initial state | | New state after |
| (empty array) | <--------+ | ADD_BOOKING |
+-----------------+ +-----------------+
|
v
+----------------+
| Reducer |
+----------------+
|
v
+-----------------+ +-----------------+
| Initial state | | New state after |
| (empty array) | <--------+ | DELETE_BOOKING |
+-----------------+ +-----------------+

In the diagram, the component dispatches an action to the store, which is handled by the reducer function. The reducer function returns a new state object based on the action type, which is then used to update the application state. The updated state is then passed back to the component via the useSelector hook, which allows the component to re-render with the updated state.

Note that the action types, action creators, and reducer function are all organized together in the booking folder for easy maintenance and scalability.

Step 4: Inside the redux folder, create a new file called store.js. This file will contain the code for creating the Redux store. In this file, we'll import the createStore function from the redux package and the booking reducer from the bookingReducer.js file.

javascriptCopy codeimport { legacy_createStore as createStore } from 'redux'
import bookingReducer from "./Booking/bookingReducer";

const store = createStore(bookingReducer);

export default store;

In the code above, we created a new Redux store using the createStore function and passed in our booking reducer. We then exported the store object so that we can use it in other parts of the application.

Note that in a larger application, you might have multiple reducers that are combined together using the combineReducers function from Redux. However, for the purposes of this tutorial, we only have one reducer for the booking feature. we will see this this in detail in following chapters.

Step 5: Coonect the whole Application with Redux Store. This makes the state values inside the store available in the whole application.

import { Provider, useSelector } from "react-redux";
import store from "./redux/store";
import BookingInput from "./components/BookingInput";

function App() {
return (
<Provider store={store}>
<BookingInput/>
</Provider>

);
}

export default App;

In the code above, we imported a function from the react-redux package: Provider. We also imported the store object that we created in the store.js file located in the redux folder. Finally, we imported the BookingInput component, which will be used to display a form for adding a new booking.

The Provider component is a special component provided by react-redux that allows us to "provide" the Redux store to all components in the application. We pass the store object as a prop to the Provider component, and all child components can then access the store using the useSelector hook.

The useSelector hook is a function provided by react-redux that allows us to select data from the Redux store. We can use this hook to retrieve data from the store and use it in our components.

In the App component, we wrap the BookingInput component in the Provider component, passing the store object as a prop. This allows the BookingInput component to access the Redux store using the useSelector hook.

Step 5: Testing the Application Finally, we’ll test the application by running the development server with npm start and making sure we can book a flight and delete it successfully.

Conclusion: In this article, we explored how to use React and Redux together to build a flight booking application. We created a Redux store, a booking reducer, and actions to add and delete bookings. We also connected React components to the Redux store using the connect function from react-redux. By following these steps, you can create a functional flight booking application using React and Redux.

--

--