ReactJS - Using Flux
ReactJS - State Management with Redux Toolkit
Section titled “ReactJS - State Management with Redux Toolkit”While Flux is a pattern, Redux is a popular library that helps implement it. Modern Redux development is greatly simplified by Redux Toolkit, which is now the recommended approach. This tutorial will guide you through setting up a simple Todo application using React and Redux Toolkit.
Step 1 - Install Redux Toolkit and React-Redux
Section titled “Step 1 - Install Redux Toolkit and React-Redux”Open your terminal or command prompt in your React project’s root directory and run:
npm install @reduxjs/toolkit react-reduxOr if you are using Yarn:
yarn add @reduxjs/toolkit react-reduxStep 2 - Create Project Structure
Section titled “Step 2 - Create Project Structure”A common practice with Redux Toolkit is to organize state logic by ‘features’ or ‘slices’. For our Todo app, we’ll create a features directory within src.
Your src folder might look something like this:
src/├── app/│ └── store.js # Redux store configuration├── features/│ └── todos/│ ├── todosSlice.js # Reducer and actions for todos│ └── Todos.jsx # React component for todos├── App.js # Main application component└── index.js # Entry point, renders AppStep 3 - Define a Redux Slice (todosSlice.js)
Section titled “Step 3 - Define a Redux Slice (todosSlice.js)”A ‘slice’ is a collection of Redux reducer logic and actions for a single feature. Redux Toolkit’s createSlice function generates action creators and action types automatically.
src/features/todos/todosSlice.js
Section titled “src/features/todos/todosSlice.js”import { createSlice } from '@reduxjs/toolkit';
let nextTodoId = 0;
const todosSlice = createSlice({ name: 'todos', initialState: [], reducers: { addTodo: { reducer(state, action) { state.push(action.payload); // Immer handles immutability here }, prepare(text) { return { payload: { id: nextTodoId++, text, completed: false } }; } }, toggleTodo(state, action) { const todo = state.find(todo => todo.id === action.payload); if (todo) { todo.completed = !todo.completed; } } }});
export const { addTodo, toggleTodo } = todosSlice.actions;export default todosSlice.reducer;Key points:
createSlicetakes a name, an initial state, and an object of reducer functions.- Reducer functions can ‘mutate’ state directly thanks to Immer, which runs under the hood in Redux Toolkit.
preparecallback inaddTodoallows customizing the action payload, here we generate a unique ID.- Action creators (
addTodo,toggleTodo) are automatically generated and exported.
Step 4 - Configure the Redux Store (store.js)
Section titled “Step 4 - Configure the Redux Store (store.js)”configureStore from Redux Toolkit simplifies store setup.
src/app/store.js
Section titled “src/app/store.js”import { configureStore } from '@reduxjs/toolkit';import todosReducer from '../features/todos/todosSlice';
export const store = configureStore({ reducer: { todos: todosReducer, // other reducers can be added here },});Step 5 - Provide the Store to React (index.js)
Section titled “Step 5 - Provide the Store to React (index.js)”Wrap your root application component with the <Provider> component from react-redux to make the store available to all components.
src/index.js
Section titled “src/index.js”import React from 'react';import ReactDOM from 'react-dom/client';import { Provider } from 'react-redux';import { store } from './app/store';import App from './App';import './index.css'; // Assuming you have some basic styling
const root = ReactDOM.createRoot(document.getElementById('root'));root.render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode>);Step 6 - Use Redux State and Actions in Components (Todos.jsx and App.js)
Section titled “Step 6 - Use Redux State and Actions in Components (Todos.jsx and App.js)”We’ll use the useSelector hook to read data from the store and useDispatch to dispatch actions.
src/features/todos/Todos.jsx
Section titled “src/features/todos/Todos.jsx”import React, { useState, useRef } from 'react';import { useSelector, useDispatch } from 'react-redux';import { addTodo, toggleTodo } from './todosSlice';
function Todos() { const todos = useSelector(state => state.todos); const dispatch = useDispatch(); const [text, setText] = useState(''); const inputRef = useRef(null);
const handleAddTodo = (e) => { e.preventDefault(); if (text.trim()) { dispatch(addTodo(text.trim())); setText(''); inputRef.current.focus(); } };
return ( <div> <form onSubmit={handleAddTodo}> <input type="text" value={text} onChange={(e) => setText(e.target.value)} ref={inputRef} placeholder="What needs to be done?" /> <button type="submit">Add Todo</button> </form> <ul> {todos.map(todo => ( <li key={todo.id} onClick={() => dispatch(toggleTodo(todo.id))} style={{ textDecoration: todo.completed ? 'line-through' : 'none', cursor: 'pointer' }} > {todo.text} </li> ))} </ul> </div> );}
export default Todos;Now, let’s integrate the Todos component into App.js.
src/App.js
Section titled “src/App.js”import React from 'react';import Todos from './features/todos/Todos';import './App.css'; // Assuming you have some basic styling
function App() { return ( <div className="App"> <header className="App-header"> <h1>Todo List with Redux Toolkit</h1> </header> <main> <Todos /> </main> </div> );}
export default App;With these steps, you have a functioning Todo application using React and Redux Toolkit. You can add new todos and toggle their completion status. This demonstrates the modern, simplified way of working with Redux.
Common Pitfalls & Further Learning:
- Forgetting to wrap
Appin<Provider>. - Incorrectly selecting state with
useSelector(ensure yourstate.featureNamematches your store configuration). - For more complex applications, explore asynchronous logic with
createAsyncThunkand middleware like Redux Thunk (included by default in Redux Toolkit). - Refer to the official Redux Toolkit documentation for advanced patterns: https://redux-toolkit.js.org/