Combining the Puzzle Pieces
Let's now look at a working to-do list application that uses the concepts learned in the previous lessons.
We'll cover the following...
To-do list app example
We now know how to use the connect() method and why we need a Provider. Let’s look at a more detailed and complete example that outlines a totally functional to-do list app. It allows us to add new to-do items, mark them as complete or not, and allows us to remove them if we want:
import React, { useState } from 'react';
import { connect } from 'react-redux';
import { addTodo, removeTodo, changeStatus } from './store/todos/actions';
const TodoList = (props) => {
const [todoText, setTodoText] = useState('');
return (
<div>
<p>{props.todos.length} Todos.</p>
<ul>
{props.todos.map((todo) => (
<li key={todo.id}>
<button
type="button"
onClick={() => {
props.removeTodo(todo.id);
}}
>
remove
</button>
<label
style={{ textDecoration: todo.done ? 'line-through' : 'none' }}
>
<input
type="checkbox"
name={todo.id}
checked={Boolean(todo.done)}
onChange={(e) => {
const { name, checked } = e.target;
props.changeStatus(name, checked);
}}
/>
{todo.text}
</label>
</li>
))}
</ul>
<input onChange={(e) => setTodoText(e.target.value)} value={todoText} />
<button
type="button"
onClick={() => {
props.addTodo(todoText);
setTodoText('');
}}
>
add
</button>
</div>
);
};
const mapStateToProps = (state) => ({
todos: state.todos,
});
const mapDispatchToProps = {
addTodo,
removeTodo,
changeStatus,
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(TodoList);
We’ve defined the todosReducer as well as addTodo, removeTodo, and changeStatus actions. To aid readability, both reducers and actions have been extracted into their own files within the ./store/todos directory.
Note: There’s always heated debate about how folders and files should be structured within an application. Some find a separation by the domain (for example,
todos,user,repositories, etc.) and according to type ( ...