How to get started with Redux Toolkit 
Tags: react, redux, webdev, beginners
Published: 2020-08-26 01:43:52

# What is Redux Toolkit?

To sum it up. It's an easier way to setup and get going with Redux. 

We've all been there when it comes to trying to configure a Redux store and in turn, we're left bewildered by the thought it. Or perhaps, it takes too much boilerplate code to get up and running. These are just some of the concerns that Redux Toolkit aims to solve. 

> The Redux Toolkit package is intended to be the standard way to write Redux logic.

> We can't solve every use case, but in the spirit of create-react-app and apollo-boost, we can try to provide some tools that abstract over the setup process and handle the most common use cases, as well as include some useful utilities that will let the user simplify their application code.

> Because of that, this package is deliberately limited in scope. It does not address concepts like "reusable encapsulated Redux modules", data caching, folder or file structures, managing entity relationships in the store, and so on.                                        - Redux Toolkit docs

# Prerequisite

- Basics of Redux and React

# Installation

Run the following command to install it 

```bash
# NPM
npm install --save redux react-redux @reduxjs/toolkit

# Yarn
yarn add --save redux react-redux @reduxjs/toolkit
```

[Redux.org](http://redux.org) recommends that you structure it in the following ways: 

- Feature folder
    - All files for a feature in a single folder
- Ducks pattern
    - All Redux logic for a feature in a single file

# How to setup the Redux Store

I'm going to create a folder called `store` and create a file called `index.js`

```jsx
src > store > index.js

import { configureStore } from '@reduxjs/toolkit'
import { combineReducers } from 'redux'

const reducer = combineReducers({
 // add reducers
})

const store = configureStore({
  reducer,
})

export default store;
```

You can also do it this way:

```jsx
src > index.js

import React from 'react'
import { render } from 'react-dom'

import { configureStore } from '@reduxjs/toolkit'
import { Provider } from 'react-redux'

import App from './App'

import rootReducer from './whereeverthislocated'

import './index.css'

const store = configureStore({ reducer: rootReducer })

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

```

# What are slices?

Redux Toolkit has this thing called slices and essentially, it automatically generates reducers, action types, and action creators. Each `slice` file lives inside a folder inside of `src` called `slices` 

## The initial state

```jsx
src > slices > count.js

import { createSlice } from '@reduxjs/toolkit'

export const initialState = {
  count: 0
}
```

## Creating a slice

```jsx
src > slices > count.js

const countSlice = createSlice({
  name: "count",
  initialState,
  reducers: {
    increment: (state) => {
      state.count = state.count + 1;
    },
    decrement: (state) => {
      state.count = state.count - 1;
    }
  }
});
export const { increment, decrement } = countSlice.actions;
export default countSlice.reducer
```

# Getting Redux state in a React component

Before, we used `mapStateToProps` with the `connect()` function to get the state from the store and in Redux Toolkit, that is still a viable option. However, with the addition of Hooks, we can use `useDispatch` and `useSelector`

Here's a little bit about each hook:

1. `useDispatch`
    - Used to "dispatch" actions
2. `useSelector`
    - Allows you to "select" data from the Redux store state, using a selector function.

```jsx
App.js

import React from "react";
import "./styles.css";
import { useDispatch, useSelector } from "react-redux";

import { increment, decrement } from "../slices/count";

export default function App() {
  const dispatch = useDispatch();
  const { count } = useSelector((state) => state).countSlice;

  const handleUp = () => {
    dispatch(increment());
  };
  const handleDown = () => {
    dispatch(decrement());
  };
  return (
    <div className="App">
      <h1>My Amazing Counter</h1>

      <h2>Current Count: {count}</h2>
      <button onClick={handleUp}>UP</button>
      <button onClick={handleDown}>DOWN</button>
    </div>
  );
}
```
{% codesandbox intro-redux-toolkit-counter-7ompi %}

For `useSelector`, you can also predefine what you want in the `count.js` file. For example:

```jsx
src > slices > count.js 

// A selector
export const countSelector = (state) => state.count
```

And then use that in the `App.js` file,

```jsx
App.js

const App = () => {
	const { count } = useSelector(countSelector)
	...
}
```

# Fetching data from an API

This counter example is pretty basic and you're more likely going to be working with an API of some sorts so let's learn how to fetch and save it to the store. 

For this, I'm going to be using the Github API. In the `slices` folder, create a file called `repo.js` and add the following: 

```jsx
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";

export const initialState = {
  loading: false,
  hasErrors: false,
  repos: []
};

const reposSlice = createSlice({
  name: "repos",
  initialState,
  reducers: {
    getRepos: (state) => {
      state.loading = true;
    },
    getReposSucess: (state, { payload }) => {
      state.repos = payload;
      state.loading = false;
      state.hasErrors = false;
    },
    getReposFailure: (state) => {
      state.loading = false;
      state.hasErrors = true;
    }
  }
});

export const { getRepos, getReposSucess, getReposFailure } = reposSlice.actions;

// The reducer
export default reposSlice.reducer;

export const fetchRepos = createAsyncThunk(
  "repos/fetchRepos",
  async (thunkAPI) => {
    // Set the loading state to true
    thunkAPI.dispatch(getRepos());

    try {
      const response = await fetch(
        "https://api.github.com/search/repositories?q=react&page=1&per_page=10",
        {
          method: "GET",
          headers: {
            Accept: "application/vnd.github.v3+json"
          }
        }
      );
      const data = await response.json();
      // Set the data 
      thunkAPI.dispatch(getReposSucess(data));
    } catch (error) {
      // Set any erros while trying to fetch
      thunkAPI.dispatch(getReposFailure());
    }
  }
);
```

A little bit about `createAsyncThunk`:

- A `thunk` is a function that gets returned by another function
- `createAsyncThunk` will run a callback when dispatched as well as lifecycle actions based on the returned promise

To learn more about `createAsyncThunk` you can go [here](https://redux-toolkit.js.org/api/createAsyncThunk)

### Displaying the repos

In `App.js`, add the following:

```jsx
App.js

import React, { useEffect } from "react";
import "./styles.css";
import { useDispatch, useSelector } from "react-redux";
import { fetchRepos } from "../slices/repo";

export default function App() {
  const dispatch = useDispatch();
  const { loading, hasErrors, repos } = useSelector(
    (state) => state
  ).reposSlice;

  useEffect(() => {
    dispatch(fetchRepos());
  }, [dispatch]);

  if (loading) {
    return <p>Loading...</p>;
  } else if (hasErrors) {
    return <p>Oh no error! Display something here.</p>;
  }
  console.log(repos.items);
  return <div className="App">loaded</div>;
```

{% codesandbox intro-redux-toolkit-data-fetchi-70qco %}


Similar to our counter example, we're pretty much doing the same steps except we added in the `useEffect` hook to fetch our data.

### If you want to pass parameters to your API call

```jsx
App.js
. . .

useEffet(() => {
	dispatch(fetchRepos("react"))
}, [dispatch])

. . .
```

```jsx
src > slices > repo.js 

export const fetchRepos = createAsyncThunk(
  "repos/fetchRepos",
  async (paramNameHere, thunkAPI) => {
		console.log(paramNameHere)
    . . .
  }
);
```

And that's it! 

### Conclusion

In this post, we learned what Redux Toolkit is, how to setup our store, update our store and even learned how to fetch data and save it to the store as well. Redux is complicated and we're probably going to bump into it again so hopefully Redux Toolkit can help you as it has helped me. 

Thanks for reading and if I missed something in this post please comment down below, I'm not an expert so feedback is always appreciated.

Cover Image from: [https://miro.medium.com/max/800/1*4sxOPaVNwxrfZ9uxVbUaKg.jpeg](https://miro.medium.com/max/800/1*4sxOPaVNwxrfZ9uxVbUaKg.jpeg)