🚀 Redux Todo List Refactor: Presentational & Container Components
Refactoring a Redux Todo List: Presentational and Container Components
In the world of React development, maintaining a clean and manageable codebase is crucial for both scalability and maintainability. One effective way to achieve this is by separating components into presentational and container components. In this blog post, we’ll explore how to refactor a Redux Todo List application by implementing this separation.
Understanding Presentational and Container Components
Before diving into the refactoring process, let's clarify the concepts of presentational and container components:
Presentational Components: These components are primarily focused on how things look. They receive data and callbacks exclusively via props, and they don’t manage their own state (except for UI state). Presentational components are typically stateless functional components.
Container Components: These components are concerned with how things work. They handle fetching data, managing state, and passing data down to presentational components. Container components are often class components or stateful functional components that utilize hooks.
This separation of concerns enhances the reusability of presentational components and simplifies testing.
Setting Up the Project
If you’re starting from scratch, ensure you have a basic Redux Todo List setup. Your project should include:
- React
- Redux
- Redux Thunk (for async actions)
If you haven't already set up your project, you can use Create React App with Redux and Thunk.
npx create-react-app redux-todo-list
cd redux-todo-list
npm install redux react-redux redux-thunk
Initial Project Structure
A typical folder structure for your Todo List might look like this:
/src
/components
TodoList.js
TodoItem.js
/containers
TodoListContainer.js
/redux
actions.js
reducers.js
store.js
Step 1: Create Presentational Components
TodoItem.js
First, we’ll create the TodoItem component, which is a presentational component that displays a single todo item.
// src/components/TodoItem.js
import React from 'react';
const TodoItem = ({ todo, onToggle }) => {
return (
<li
onClick={onToggle}
style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}
>
{todo.text}
</li>
);
};
export default TodoItem;
TodoList.js
Next, we’ll create the TodoList component, which will render a list of TodoItem components.
// src/components/TodoList.js
import React from 'react';
import TodoItem from './TodoItem';
const TodoList = ({ todos, onToggleTodo }) => {
return (
<ul>
{todos.map(todo => (
<TodoItem
key={todo.id}
todo={todo}
onToggle={() => onToggleTodo(todo.id)}
/>
))}
</ul>
);
};
export default TodoList;
Step 2: Create Container Component
TodoListContainer.js
Now that we have our presentational components, we need to create the container component that connects the Redux store to our presentational components.
// src/containers/TodoListContainer.js
import React from 'react';
import { connect } from 'react-redux';
import TodoList from '../components/TodoList';
import { toggleTodo } from '../redux/actions';
const TodoListContainer = ({ todos, toggleTodo }) => {
return <TodoList todos={todos} onToggleTodo={toggleTodo} />;
};
const mapStateToProps = (state) => ({
todos: state.todos,
});
const mapDispatchToProps = {
toggleTodo,
};
export default connect(mapStateToProps, mapDispatchToProps)(TodoListContainer);
Step 3: Update the Redux Logic
actions.js
Make sure your actions are set up correctly to handle toggling a todo item.
// src/redux/actions.js
export const TOGGLE_TODO = 'TOGGLE_TODO';
export const toggleTodo = (id) => ({
type: TOGGLE_TODO,
payload: id,
});
reducers.js
Ensure your reducer handles the toggle action appropriately.
// src/redux/reducers.js
import { TOGGLE_TODO } from './actions';
const initialState = {
todos: [
{ id: 1, text: 'Learn React', completed: false },
{ id: 2, text: 'Learn Redux', completed: false },
],
};
const todoReducer = (state = initialState, action) => {
switch (action.type) {
case TOGGLE_TODO:
return {
...state,
todos: state.todos.map(todo =>
todo.id === action.payload ? { ...todo, completed: !todo.completed } : todo
),
};
default:
return state;
}
};
export default todoReducer;
Step 4: Connecting Everything in App.js
Finally, connect everything in your App.js.
// src/App.js
import React from 'react';
import { Provider } from 'react-redux';
import store from './redux/store';
import TodoListContainer from './containers/TodoListContainer';
const App = () => {
return (
<Provider store={store}>
<div>
<h1>Todo List</h1>
<TodoListContainer />
</div>
</Provider>
);
};
export default App;
Conclusion
Congratulations! You’ve successfully refactored your Redux Todo List application by separating presentational and container components. This approach not only cleans up your code but also enhances the reusability and testability of your components.
By keeping your business logic in container components and your UI logic in presentational components, you can ensure that your application remains scalable and maintainable as it grows.
Feel free to explore further by adding more features, such as filtering todos or implementing a form to add new todos. Happy coding!
Connect with SkillBakery Studios
Explore more tutorials, tools, and resources:
Posted by SkillBakery Studios


No comments:
Post a Comment