How to Create Simple Redux Store with Redux Toolkit
Tags: webdev, react, tutorial, redux
Published: 2021-11-08 06:55:03

# How to Create Simple Redux Store with Redux Toolkit

Setting up even a simple Redux store used to be hard. Not anymore. With the help of Redux Toolkit we can create Redux stores much faster and with less code. This tutorial will help you learn how to use Redux Toolkit to create such a simple store and how to implement it in your React app.

Demo on [Codesandbox].

## About the project and dependencies

In this tutorial we will take a look at how to create a simple redux store with [Redux Toolkit]. The app we will be working on will be an app for creating books collection. It will allow users to add books to collections and remove them. It will also show all books currently in collection.

The main app state for book collection will be the Redux state. Adding and removing books will be handled by reducer functions. We will create this app with the [create-react-app]. This will give us what we need to get the React app up and running. For Redux, we will need two additional dependencies.

The first dependency will be [react-redux], version 7.2.6. This library contains official React bindings for Redux. Second dependency we will need is [@reduxjs/toolkit], version v1.6.2. This library contains tools that make working with Redux much easier. This also includes setting up a redux store.

This tutorial will also use [uuid] library, version 8.3.2. This library is not necessary for the Redux state. We will use it to generate unique ids for added books. These ids will make it easier to remove specific book from collection. This is all we need to get started.

## Creating Redux store

Let's start with the most interesting part, creating the Redux store. To keep the project tidy, all store-related stuff will be in `/store` directory, right inside `/src`. The `/store` directory will contain two files: `books.js` and `index.js`. The `books.js` will contain Redux state slice for book collection.

The `index.js` will contain a very simple setup for the Redux store for our React app.

### Redux state slice

The first part of the redux state is will be the redux state slice. We will create the redux slice with `createSlice()`, a method provided by `@reduxjs/toolkit`. This method allows us to do a couple of things. First, it allows us to define the initial state for our store, the book collection.

It also allows us to define reducer functions for the same store. We will use these reducers later to add books to collection and also to remove them. The initial state for the store will be an object with single property, `books`. The value of this property will be an empty array.

For this tutorial we will need two reducers. One will be for adding new book to the Redux store. The second will be removing book from the store. We can call these reducers `addBook` and `removeBook`. We will define these reducers in an object we will use as a value for `reducers` property of `createSlice()` method.

The last thing for the `createSlice()` method is adding `name` property with some name for the store. This is used by Redux toolkit to generate required actions for our Redux store. When we have this setup, the `createSlice()` method will automatically generate two things: actions and reducer for our new slice.

It used to be that we had to create these two by ourselves. This is no longer necessary thanks to the Redux toolkit and the whole process is much easier, as you can see. Now, we just have to export those actions and the reducer and we are done here.

```js
// src/store/books.js

// Import createSlice() from Redux toolkit:
import { createSlice } from '@reduxjs/toolkit'

// Initial state for Redux store:
const initialState = {
  books: [],
}

// Create Redux state slice
const booksSlice = createSlice({
  name: 'books',
  initialState, // Define initial state
  reducers: {
    // Define reducers
    addBook: (state, action) => {
      // Reducer for adding new book to collection
      // Create new state by taking existing books
      // and combining them with newly added book:
      state.books = [...state.books, action.payload]
    },
    removeBook: (state, action) => {
      // Reducer for removing book from collection
      // Filter out a book that matches provided "id":
      state.books = state.books.filter((b) => b.id !== action.payload.id)
    },
  },
})

// Export actions generated by "createSlice()":
export const { addBook, removeBook } = booksSlice.actions

// Export reducer generated by "createSlice()":
export default booksSlice.reducer
```

### Configuring Redux store

We have the setup for Redux state slice, but there is a bit more we have to do. We have to create the Redux store itself and connect it to the reducer generated for our books slice. We will do this by using another method provided by Redux toolkit called `configureStore()`.

This method accepts one parameter, configuration object for the Redux store. Right now, we need to define only one property of this object, `reducer`. The value of this property will be an object with the reducer we want to use. This will be the `booksSlice.reducer` we recently worked with in `books.js`.

We have to import this reducer and add it to the `reducer` object in store config. After that, we are done as well.

```js
// src/store/index.js

// Import configureStore() from Redux toolkit:
import { configureStore } from '@reduxjs/toolkit'

// Import books reducer:
import booksReducer from './books'

// Create Redux store:
export const store = configureStore({
  reducer: {
    booksReducer, // Add books reducer
  },
})
```

### Adding Redux provider

Both, Redux slice and store are ready. There is one last step we have to make. We have to create Redux provider and connect it with the store we just finished. This will be very fast. We have to go to the main file that renders the main React `App` component. This will probably be `index.js` in `src/`.

Here, we have to import `Provider` component from `react-redux` library and our Redux store, we exported from `src/store/index.js`. We will add the `Provider` component to the component tree and set our store as a value for Provider's `store` prop. This will make the store available for the whole app.

```js
// src/index.jsx

// Import React deps:
import { StrictMode } from 'react'
import ReactDOM from 'react-dom'
// Import Redux provider:
import { Provider } from 'react-redux'

// Import some styles:
import './styles.css'

// Import redux store:
import { store } from './store'

// Import main App component:
import { App } from './App'

// Render the React app:
const rootElement = document.getElementById('root')
ReactDOM.render(
  <StrictMode>
    {/* Add Redux provider */}
    <Provider store={store}>
      <App />
    </Provider>
  </StrictMode>,
  rootElement
)
```

## The Form component

The first component for our books collection app will be form for adding books. This component will have its own local state ([useState]), for storing information about book's title and author. We will store these data in Redux store using `dispatch()` method returned from `useDispatch()` hook that is provided by `react-redux`.

To add new book, we use the `addBook` reducer we exported from `src/store/books.js`. We will pass this reducer to the `dispatch()` method. Payload for the `addBook` reducer will be data for the book: title, author and unique id generated by `uuid`. After new book is added, we will reset local state for title and author.

```jsx
// src/Form.jsx

// Import dependencies:
import { memo, useCallback, useState } from 'react'
import { useDispatch } from 'react-redux'
import { v4 as uuidV4 } from 'uuid'

// Import addBook reducer:
import { addBook } from './store/books'

// Create Form component:
export const Form = memo(() => {
  // Prepare Redux dispatch method:
  const dispatch = useDispatch()

  // Create form states:
  const [bookTitle, setBookTitle] = useState('')
  const [bookAuthor, setBookAuthor] = useState('')

  // Add form onSubmit handler:
  const onFormSubmit = useCallback(
    (event) => {
      event.preventDefault()

      // Dispatch addBook reducer with payload
      // containing data for new book:
      dispatch(
        addBook({
          bookTitle,
          bookAuthor,
          id: uuidV4(),
        })
      )

      // Reset form states:
      setBookTitle('')
      setBookAuthor('')
    },
    [bookAuthor, bookTitle, dispatch]
  )

  return (
    <form onSubmit={onFormSubmit}>
      <fieldset>
        <label htmlFor="title">Book title</label>
        <input
          type="text"
          id="title"
          value={bookTitle}
          onChange={(event) => setBookTitle(event.target.value)}
        />
      </fieldset>

      <fieldset>
        <label htmlFor="author">Book author</label>
        <input
          type="text"
          id="author"
          value={bookAuthor}
          onChange={(event) => setBookAuthor(event.target.value)}
        />
      </fieldset>

      <fieldset>
        <button type="submit">Add book</button>
      </fieldset>
    </form>
  )
})
```

### The BookList component

Thanks to the form, we can store books in our Redux store. Next thing we can do is create some list showing all books that are currently in the store. We can also add some button to remove specific book from the list, and the store. To do this, we will have to do a couple of things.

First, we will again have to use the `useDispatch()` hook to get the `dispatch()` method so we can update our store. Now, the reducer we will dispatch will be the `removeBook`. We will import this reducer from `src/store/books.js`. We will handle removing books with new handler function called `onBookRemove()`.

This function will accept one parameter: `bookId`. It will pass this id as a payload to the `removeBook` reducer, and pass this reducer to the `dispatch()` method. The payload will be an object with `id` property and id of the book we want to remove. In order to list the books in store, we will need to get them somehow.

We can get those books by using the `useSelector()` hook, also provided by `react-redux`. This hook allows us to access the redux store's state, the books state in our case. All we need is to provide this hook with a selector function to get the data we want.

The hook passes `state` as an argument to the selector function. We will use this argument to get the `booksReducer` we registered when we configured the Redux store (in `src/store/index.js`). This reducer contains the slice we created for our books collection. The name of this slice is `books`.

We defined this name in `src/store/books.js`. It is the `name` property in `createSlice()` method. We will now use this name to access the books slice. The state of this slice is the array for our books collection. When we have this, we can use `map()` to iterate over the books array to generate and display a list of all books in collection.

```jsx
// src/BookList.jsx

// Import dependencies:
import { memo, useCallback } from 'react'
import { useDispatch, useSelector } from 'react-redux'

// Import removeBook reducer:
import { removeBook } from './store/books'

// Create BooksList component:
export const BooksList = memo(() => {
  // Get books from Redux store:
  const books = useSelector((state) => state.booksReducer.books)
  // Prepare dispatch method:
  const dispatch = useDispatch()

  // Create handler for removing book:
  const onBookRemove = useCallback(
    (bookId) => {
      dispatch(removeBook({ id: bookId }))
    },
    [dispatch]
  )

  return (
    <div className="booklist">
      {books.map((book) => (
        <div key={book.bookTitle} className="book">
          {`${book.bookTitle} by ${book.bookAuthor}`}
          <button
            className="removeButton"
            onClick={() => onBookRemove(book.id)}
          >
            &times;
          </button>
        </div>
      ))}
    </div>
  )
})
```

## The App component

Redux, form and book list components are ready. We can now put these components together in the `App` component. Along with this, we can also add a heading showing how many books we have in our collection. We will get this number by using the `useSelector` hook to get the books state.

In this case, instead of asking for `state.booksReducer.books` we can ask directly for the number of books in the state. We can do this by adding the `length` property: `state.booksReducer.books.length`. This will return the number of books in the store instead of the array itself.

```jsx
// src/App.jsx

// Import dependencies:
import { memo } from 'react'
import { useSelector } from 'react-redux'

// Import components:
import { BooksList } from './BooksList'
import { Form } from './Form'

// Create App component:
export const App = memo(() => {
  // Get books from Redux store:
  const booksCount = useSelector((state) => state.booksReducer.books.length)

  return (
    <div className="app">
      <h1>Books in collection: {booksCount}</h1>

      <Form />

      {booksCount > 0 && <BooksList />}
    </div>
  )
})
```

## The index file

The `index.jsx` where we added the Redux `Provider` component stayed the same. No change is necessary here.

```jsx
// src/index.jsx

// Import React deps:
import { StrictMode } from 'react'
import ReactDOM from 'react-dom'
// Import Redux provider:
import { Provider } from 'react-redux'

// Import some styles:
import './styles.css'

// Import redux store:
import { store } from './store'

// Import main App component:
import { App } from './App'

// Render the React app:
const rootElement = document.getElementById('root')
ReactDOM.render(
  <StrictMode>
    {/* Add Redux provider */}
    <Provider store={store}>
      <App />
    </Provider>
  </StrictMode>,
  rootElement
)
```

## Conclusion: How to create simple Redux store with Redux toolkit

The whole flow of setting up even a simple Redux store used to be tedious and lengthy. Developers had to write a lot of code to just get started. This is no longer the case thanks to Redux toolkit. I hope that this tutorial helped you learn how to create a simple Redux store and how to implement it in your React app.

[codesandbox]: https://codesandbox.io/s/redux-toolkit-demo-6tgyq
[redux toolkit]: https://redux-toolkit.js.org/
[create-react-app]: https://create-react-app.dev/
[@reduxjs/toolkit]: https://www.npmjs.com/package/@reduxjs/toolkit
[react-redux]: https://www.npmjs.com/package/react-redux
[uuid]: https://www.npmjs.com/package/uuid
[usestate]: https://blog.alexdevero.com/react-usestate-hook-in-action/