React with Redux, Tailwind and More

Intro

React is currently the most popular front end framework. We will set up a react project and use Vite for tooling and packaging, Redux for managing state of the application and Tailwind CSS for styling the UI.

NOTE: I might update this post from time to time with info about more packages

Create project

NOTE: We will use Bun to install and manage packages. These steps will also work for other similar package managers like NPM or PNPM. Check out their installation guides on their respective websites

Setup a new project with create-vite. When prompted select React framework and Typescript + SWC variant

% bunx create-vite <name>

✔ Select a framework: › React
✔ Select a variant: › TypeScript + SWC

Change directory to the project folder and run

% bun install

This will add the dependencies needed for React and Typescript.

NOTE: The next step is not required. Revert the changes if you get build errors using bun

Since we are using Bun, we can modify the package.json and add --bun flag to dev, build and preview scripts to run the Vite CLI using bun instead of node

Ref: https://bun.sh/guides/ecosystem/vite

{
  "scripts": {
    "dev": "bunx --bun vite",
    "build": "tsc && bunx --bun vite build",
    "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
    "preview": "bunx --bun vite preview"
  },
}

We can now run the above scripts with bun run <script_name>

We can now make changes to the project files. Run bun run dev to start the development mode. Go to the URL int the output to see the default project. Change the site title in index.html file. Live reload should automatically update it on the website.

Add TailwindCSS

Vite has build in support for PostCSS, so we will use Tailwind as a PostCSS plugin.

Ref: https://vitejs.dev/guide/features#postcss
Ref: https://tailwindcss.com/docs/guides/vite#react

% bun install -D tailwindcss postcss autoprefixer

We also need to initialize Tailwind and PostCSS configuration files. This step will create two files in the project directory, one for Tailwind and one for PostCSS

% bunx tailwindcss init -p

Created Tailwind CSS config file: tailwind.config.js
Created PostCSS config file: postcss.config.js

The command above automatically sets tailwind and autoprefixer plugins in PostCSS config file

We do, however, need to make changes to Tailwind config file to tell it where the CSS utility classes will be used in our project. We can add the index.html file and all files in the src directory in the content section of tailwind.config.js

content: [
  "./index.{js,ts,jsx,tsx}",
  "./src/**/*.{js,ts,jsx,tsx}",
],

At this point the complete tailwind.config.js file should look like

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.{js,ts,jsx,tsx}",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {},
  plugins: [],
}

Now we add the Tailwind import directives in our index.css

@tailwind base;
@tailwind components;
@tailwind utilities;

NOTE: We can remove the unused CSS in index.css and src/App.css

Add Redux

Redux Toolkit is currently the recommended way to use Redux in React projects. Let’s add the required packages

% bun install @reduxjs/toolkit react-redux

Create a directory called state under src. We will use this directory to keep files related to state.

We can create a state store which will keep the state of our application. Create a new file src/state/store.ts with the following contents

import { configureStore } from '@reduxjs/toolkit';

export const store = configureStore({
    reducer: {},
});

export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

This will configure our store and create the types for accessing state and dispatching events.

NOTE: This is an empty store with no state or actions. Depending on our project requirements, we will add reducers and actions (not covered in this post). Check out some of my project posts for them.

Now, we need to warp our App component with Redux state provider so that the state is accessible anywhere in our application. In src.main.tsx add imports

import { Provider } from 'react-redux'
import { store } from './state/store'

and change

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)

to

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
      <Provider store={store}>
        <App />
      </Provider>
  </React.StrictMode>,
)

Now we can access state (eg. some_reducer.some_state) anywhere in our application using

import { useSelector } from "react-redux";
import { RootState } from "./state/store";

const x = useSelector((state: RootState) => state.some_reducer.some_state);

We can also dispatch actions (eg. some_action from someSlice) using

import { useDispatch } from "react-redux";
import { AppDispatch } from "./state/store";
import { some_action } from "./state/someSlice";

const dispatch = useDispatch<AppDispatch>();
dispatch(some_action());

Optional packages

Font Awesome

If we need to add fonts from Font Awesome, we can add the core svg and react component packages

bun install @fortawesome/fontawesome-svg-core @fortawesome/react-fontawesome@latest

Then we can add the icon bundles we need

bun install @fortawesome/free-solid-svg-icons
bun install @fortawesome/free-regular-svg-icons
bun install @fortawesome/free-brands-svg-icons

The above steps can all be done at the same time with

bun install @fortawesome/fontawesome-svg-core @fortawesome/react-fontawesome@latest @fortawesome/free-solid-svg-icons @fortawesome/free-regular-svg-icons @fortawesome/free-brands-svg-icons

Then we can import individual icons and use them whenever needed

sample.tsx

import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faQuoteLeft } from "@fortawesome/free-solid-svg-icons";

function Sample() {
  return <FontAwesomeIcon icon={faQuoteLeft} />
}