First of all, the main page is index.html. They have a div id=”root”
A rendered JSX from index.js will be inserted to this block. index.js includes code from App.js component.
App.js uses react-router-dom that uses React Router to bind DOM.
React Router dynamically render component pages/Home where you are now. (so the entire app doesn't reloading when a link is opens, only necessary elements refreshing)
Home.js component uses components/navbar.js to add navigation bar on the top of the app.
The pages/Todos.js component placed on the /todo path, that can be reached by clicking to the link on the top right corner on navbar.
The Redux implementation of this app placed here: https://github.com/Gogn/react-Todo-app
Project tree
. ├── App.js ├── components │ ├── navbar.js │ └── todo.js ├── index.css ├── index.js ├── pages │ ├── Home.js └── Todos.jsTodos.js have a local state that have a array of objects.
Todos.js include list of todos from components/todo.js by mapping state.todos: this.state.todos.map((todo, id) => ( ... ), so every todo object from state.todos array will be shown from components/todo.js with parameters: 'todo={todo}, key={id}, doneTodo={this.doneTodo}, deleteTodo={event => this.deleteTodo(id)}'
- todo - is the current state.todos[] object from map method
- key - is necessary parameter for the map method
- doneTodo - is the function for update state.todos.done parameter
- deleteTodo - is the function to delete todo object from state.todos array
So when you clicking on the todo element or delete button the components/todo.js calling function from props and action from pages/Todos.js is triggered
pages/Todos.js also have the input that triggered addTodo function that update state.todos.todoNew. After state.todos.todoNew was updated, new todo can be stored by clicking on "Add todo" button, that triggered addTodo function and update the state.
So pages/Todos.js have a state which means the Todos.js is stateful component.
The state of Todo.js holds data which can be rendered to display the required data.
Project tree
.
├── App.js
├── components
│ ├── navbar.js
│ └── todo.js
├── index.css
├── index.js
├── pages
│ ├── Home.js
│ └── Todos.js
└── store
├── Actions
│ ├── actions.js
│ └── actionTypes.js
├── index.js
└── Reducers
├── rootReducer.js
└── todoReducer.js
Redux is a library that let use one centralizing state and logic component for whole app.
If the app will need a states (or logic functions) for several components, Redux allow describe it in centralized file. Without Redux, for this, it would be necessary to add the desired state and functions to each component, which can be confusing if there are many such components. In this app we have only one component with state\logic - Todos.js so in this case Redux may be redundant. It's useful for a large apps.
This app uses Redux library along with react-redux that lets easily bind components with Redux store.
Redux/react-redux connect to the app in a file index.js. 'const store = createStore(rootReducer)' tell that store/Reducers/rootReducer.js is the main reducer of the app.
rootReducer connect all reducers used in the app. In this app we have only one reducer so rootReducer export only store/Reducers/todoReducer.js via combineReducers function.
Reducers produce the state of app.
Next, in index.js the app formed as App.js component inside a Provider that receive store via react-redux library, so every component gain access to store.
Next, the store/Actions/actions.js declare what action needs to perform on the state.
actions.js uses variables from store/Actions/actionTypes.js that describe what action needs to do.
Every function in actions.js have an object with type of action and payload with necessary data that will be passed to Reducer
As it mentioned above, Reducers define state and actions that can be produced on state.
store/Reducers/todoReducer.js declare the initialState object with todos array of the todos.
todoReducer function determine what action has come and describe the actions to be committed.
Back to pages/Todos.js.
Todos.js have a local state that have only a todoNew object that can be update thru addTodoHandler and passed to the todoReducer
Todos.js include list of todos from components/todo.js by mapping state.todos from todoReducer.js: 'this.props.todos.map((todo, id) => ( ... )'
The todos get into props via mapStateToProps.
So every todo object from props.todos will be shown from components/todo.js with parameters: 'todo={todo}, key={id}, onDone={this.props.onDone}, onDelete={this.props.onDelete}'
- todo - is the current state.todos[] object from map method
- key - is necessary parameter for the map method
- onDone - is the function from todoReducer.js for update todos.done parameter
- onDelete - is the function from todoReducer.js to delete todo from todos array
That functions setting by mapDispatchToProps function.
So when you clicking on the todo element or delete button the components/todo.js calling function from props and action from actions.js is set, that allow todoReducer.js determine what action needs to perform.
Todos.js also have the input that triggered addTodoHandler function to set a todoNew. After todos.todoNew was updated, new todo can be stored by clicking on "Add todo" button, that triggered onSubmit function that triggered onAdd function from todoReducer.js to add a new todo.
Todo.js gets props and functions from the reducer using the connect function from react-redux library.
So we have centralized state for whole app.