Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

We use Redux for state managementRedux Toolkit is an opinionated approach to utilizing Redux(from the Redux team).

Why?

Instead of wasting time on boilerplate, you can get started immediately. The standards followed are the recommended way to write Redux logic for modern JS applications. I found that I am writing less code for core logic & can see this being utilized in any application that needs state management.

Tools:

Set-up:

This example will implement the configureStore(), useSelector(), & useDispatch() tools to run a simple CRUD application. We'll be running off create-react-app for this example.

If you haven’t a react app running yet, run:

npx create-react-app app-name

1.) In the root folder, install react-redux & redux-toolkit:

npm install react-redux @reduxjs/toolkit

2.) Configure the store in a separate store.js file:

Code Block
import { configureStore } from “@reduxjs/toolkit”;

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

The configureStore() wraps the createStore from Redux & provides simple configuration/defaults. We'll add our reducer later.

3.) From here we want to import our store & pass it as a store in our Provider.

Code Block
import { store } from './store';
import { Provider } from 'react-redux';

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

  </React.StrictMode>
);

4.) Create a features folder in the root & create a Posts.js file:

Code Block
import { createSlice } from "@reduxjs/toolkit";

const initialState = {
    value: [
        {id: '1', title: 'title 1', content: 'test'},
        {id: '2', title: 'title 2', content: 'test'},
    ]
}

export const Posts = createSlice({
    name: 'posts',
    initialState,
    reducers: {
        addPost: (state, action) => {
            state.value.push(action.payload);
        },
        deletePost: (state, action) => {
            state.value = state.value((item) => item.id !== action.payload.id)
        }
    }
})

export const { addPost, deletePost } = Posts.actions;
export default Posts.reducer;

This is the where the Action logic will go:

Code Block
addPost: (state, action) => {
            state.value.push(action.payload);
        }

state arg is the draft state provided from Immer.

action arg is the object being dispatched.

Importing Actions:

export const { addPost, deletePost } = Posts.actions;

Importing Reducers:

export default Posts.reducer;

5.) Import & add the Post reducer to our store:

Code Block
import { configureStore, createStore } from '@reduxjs/toolkit';
import postReducer from "../features/post/posts.js";

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

6.) Create a Posts.js in our component folder & import useSelector and useDispatch from the react-redux library:

Code Block
import { useSelector, useDispatch } from "react-redux";
import { addPost, deletePost } from "../posts";

const PostList = () => {
    const dispatch = useDispatch();
    const posts = useSelector(state => state.posts.value);
    const renderedPosts = posts.map((p, i) => {
        return (
            <article
                key={p.id}>
                    <h3>{p.title}{p.id}</h3>
                    <p>{p.content.substring(0, 100)}</p>
                    <button onClick={()=> {
                        dispatch(deletePost({
                            id: p.id
                        }))
                    }}>X</button>
            </article>            
        )
    })
    return (
        <section>
            <h2>Posts</h2>
            {renderedPosts}
            <button onClick={() => {
                dispatch(addPost({
                    id: posts[posts.length - 1].id + 1, 
                    title: 'Testing', 
                    content: 'woo haa'
                }))
            }}>Submit</button>
        </section>

    )
}

export default PostList;

We can access the state through:

const posts = useSelector(state => state.posts.value);

We can dispatch through:

Code Block
dispatch(addPost({
  id: posts[posts.length - 1].id + 1, 
  title: 'Testing', 
  content: 'woo haa'
}))

CreateAsyncThunk:

Summary

With Redux-toolkit we’re able to rid ourselves from having complex store configurations & unnecessary files following boilerplate. I’m planning to add more to this. Highly recommend reading through the Redux-toolkit docs for full comprehension.