Let's create a To-Do app in Redux.
I want to start a component tree that can display list of toggle-able todos.
I'm gonna bootstrap Redux instance right inside React's default index.js
, file management may come forth later in lifetime of this app. I'll write another post about storing your Redux multi-modular instance properly.
I'll build new root <TodoApp />
, which will be wired up o the Redux state management.
Then passing properties down the tree: <TodoList />
with <TodoItem />
. Latter will show the name of the todo and has a toggle on it's surface.
It's yet unreasonable to connect each of these components to Redux with connect
, because they're not far away. However consider using this HOC in larger applications.
Pretty straigthforward. Make sure you've got internet connection, and a screwdriver in case your diskette is jammed.
Step 1: Begin with creating React app
npx create-react-app todo-app
cd todo-app
Install Redux
npm i --save redux
npm start
Step 2: Redux Instance
Modify index.js
as follows to import Redux functionalities, provide Redux state to the component tree by wrapping it inside <Provider />
. TodoApp
component is connected with connect
HOC, exposing state and dispatcher to the tree
import { combineReducers, createStore } from 'redux'
import { Provider } from 'react-redux'
import TodoApp from './todoApp'
/*
* action types
* initial state
* reducers
* action creators
* reducer combination
* store declaration
*/
function mapStateToProps(state) {
return {
todos: state.todoState,
};
}
function mapDispatchToProps(dispatch) {
return {
onToggleTodo: id => dispatch(doToggleTodo(id)),
};
}
const ConnectedTodoApp = connect(mapStateToProps, mapDispatchToProps)(TodoApp);
ReactDOM.render(
<Provider store={store}>
<ConnectedTodoApp />
</Provider>,
document.getElementById('root')
);
Action Types
// action types
const TODO_ADD = 'TODO_ADD';
const TODO_TOGGLE = 'TODO_TOGGLE';
const FILTER_SET = 'FILTER_SET';
Initial State
// initial state
const todos = [
{ id: '0', name: 'Outline blog post' },
{ id: '1', name: 'Build TodoApp' },
];
Reducers
// reducers
function todoReducer(state = todos, action) {
switch(action.type) {
case TODO_ADD: {
return applyAddTodo(state, action);
}
case TODO_TOGGLE: {
return applyToggleTodo(state, action);
}
default : return state;
}
}
function applyAddTodo(state, action) {
const todo = Object.assign({}, action.todo, {completed: false});
return state.concat(todo);
}
function applyToggleTodo(state, action) {
return state.map(todo => todo.id === action.todo.id ?
Object.assign({}, todo, {completed: !todo.completed})
: todo
);
}
function filterReducer(state = 'SHOW_ALL', action) {
switch(action.type) {
case FILTER_SET: {
return applySetFilter(state, action);
}
default: return state;
}
}
function applySetFilter(state, action) {
return action.filter;
}
Action Creators
// action creators
function doAddTodo(id, name) {
return {
type: TODO_ADD,
todo: {id, name}
};
}
function doToggleTodo(id) {
return {
type: TODO_TOGGLE,
todo: { id }
};
}
function doSetFilter(filter) {
return {
type: FILTER_SET,
filter
};
}
Finally, let's combine todoReducer
with filterReducer
and create store
const rootReducer = combineReducers({
todoState: todoReducer,
filterState: filterReducer
});
const store = createStore(rootReducer);
Having installed Redux, let's build To-Do application component tree starting with a new root TodoApp
.
Step 3: Components
TodoApp
import React from 'react'
import TodoList from './todoList'
export default function TodoApp({ todos, onToggleTodo }) {
return (<TodoList
todos={store.getState().todoState}
onToggleTodo={id => store.dispatch(doToggleTodo(id))}
/>);
}
TodoList
import React from 'react'
import TodoItem from './todoItem'
export default function TodoList({ todos, onToggleTodo }) {
return (
<div>
{todos.map(todo =>
<TodoItem
key={todo.id}
todo={todo}
onToggleTodo={onToggleTodo}
/>)}
</div>
);
}
TodoItem
import React from 'react'
export default function TodoItem({ todo, onToggleTodo }) {
const { name, id, completed } = todo;
return (
<div> {name}
<button
type="button"
onClick={() => onToggleTodo(id)}
>
{completed ? "Incomplete" : "Complete"}
</button>
</div>
);
}
None of these components are aware of Redux. They simply display todos and use callbacks to propagate toggle of todo items.
The store does two things: it makes state accessible and exposes functionalities to alter the state. The todos props are passed down to the TodoApp
by retrieveing them from the store
instance. In addition, onToggleTodo
function is passed down the tree as a property, notice that it's a HOC that wraps the dispatching of an action that is created by its action creator.
Top comments (0)