react redux wiring

ref – https://react-redux.js.org/using-react-redux/connect-mapstate
https://react-redux.js.org/using-react-redux/connect-mapdispatch#connect-dispatching-actions-with-mapdispatchtoprops

Connecting React components with the Redux data store

Implementing reducers for the store

First, we create a reducer directory.
In it, we create reducer/todo.js, where we define global variable todos.
It is a reference to a reducer function with two parameters: a state, and an action object.

The state object holds initialized and current information on store’s state. The action object holds an object with a type property, and other custom properties.

Refresh the page and you’ll see a empty list.

If you want to initialize the list to having existing data, you’d initialize the state object like so:

The reason why we initialize using properties id, completed, and text is described in component TodoList.
It describes the todo property as an array.
This array contains object with attributes like so:

We will get to component TodoList later. Now refresh the page, you’ll see data in the list.

Basically, once a reducer is defined, it is combined with other reducers, and then passed into createStore so that the app can create a singleton store.

The reducer function’s 2nd parameter is an action object, which is sent by an action function, as will be described later. We know which action was triggered by looking at:

action.type

We can then work towards manipulating the state according to that action. Once, we’re done manipulating the state, we return it. This means we have updated the store.

As explained earlier, we have many different reducers, and we combine them all in order to give it to the store.
We do so by using combineReducers

Now that we have all the reducers, we simply insert them into the first parameter of createStore in our main index.js:

Notice createStore function.

redux’s createStore function

ref – https://redux.js.org/api/createstore

createStore(reducer, [preloadedState], [enhancer])

We pass in reducer functions to the createStore, which then creates a singleton store for the app to use.

TodoList component

The TodoList component is used by VisibleTodoList container. The container connects the component to the store.

TodoList component returns JSX in order to display data from each individual todo object.
However, before it does, it must define its own properties. Namely:

– todos (array)
– toggleTodo (function)

todos is an array of objects. Those objects have properties id, completed, text. This is the reason why in our reducer function, when we initialized the state object, we must initialize it according to the properties indicated here.

TodoList component has one object initializer parameter. Its properties are todos, and toggleTodo as defined above.

Now, let’s look at mapStateToProps function in container VisibleTodoList:

If a mapStateToProps function is specified (like we have), the TodoList component will subscribe to Redux store updates. This means that any time the store is updated, mapStateToProps in container VisibleTodoList will be called.

Your mapStateToProps functions are expected to return an object. This object, normally referred to as stateProps, will be merged as props to your connected component (TodoList). What gets returned from mapStateToProps is an object that identifies the property we want to change in TodoList component. We’re saying, we want to update property todos’ values.

Thus in mapStateToProps, make sure we return updated property ‘todos’.

Triggering the Action

Let’s create an ‘action’ directory, and an index file: action/index.js.

This is where all of your action functions are. In our case, we have an action function called toggleTodo

We have connected this function to a click handler in VisibleTodoList.js. Once that click handler has been invoked, we execute this action function. This action function returns an object, and this object gets passed into the ‘dispatched’ function for the store. dispatch is a function of the Redux store. You call store.dispatch to dispatch an action. This is the only way to trigger a state change.

Since we triggered a change in state, it will then execute todos reducer function in reducer/todos.js. This is because in container VisibleTodoList, it has connected the state todos array, to toggleTodo function together. Once click handler has happened for toggleTodo, it will trigger change in the todos array.

Hence, when you click on a text, you’ll see this log:


index.js:43 src/actions/index.js (ACTION) returning object of type TOGGLE_TODO and id: 0
todos.js:14 src/reducers/todo.js – (REDUCER) TOGGLE_TODO!
VisibleTodoList.js:35 src/containers/VisibileTodoList.js – mapStateToProps
TodoList.js:7 src/components/TodoList.js – TodoList
TodoList.js:8 [{…}]
Todo.js:19 src/components/Todo.js – Todo

However, notice that it then calls our connector file VisibileTodoList.js’s mapStateToProps.
This is because it’s trying to propagate updates to all that have been connected to our store.

Now that we have our reducers implemented and in place, let’s see how actions trigger those reducers.

First, in container VisibleTodoList.js, we have two parts:

– TodoList component (UI)
– Redux data store. (data)

this is where we connect our UI to data.

We import the UI component TodoList like so:

Then we connect the UI to the data via connect, mapStateToProps, and mapDispatchToProps function.

..notice the connect function.

The connect function

With React Redux, your components never access the store directly – connect does it for you. React Redux gives you two ways to let components dispatch actions:

As the first argument passed in to connect, mapStateToProps is used for selecting the part of the data from the store that the connected component needs. In our example below, TodoList is the component in need. We call connect on it to make it into a connected component.

The connected component TodoList receives dispatch calls from the action function, and then can dispatch actions onto itself via reducer functions. These reducer functions looks at the returned action object’s type property.

Therefore, we see that the connection function “connects” component TodoList to the two functions. One is to maintain state todos. The other is to dispatch actions via click handler toggleTodo.

Connecting the data

In order to connect the UI to the data store, we need to use Redux store’s dispatch function in order to apply a state change to the store. We pass in an action function into the dispatch parameter to let it know how we want this state to change:

In other words, as the second argument passed in to connect, mapDispatchToProps is used for dispatching actions to the store.

dispatch is a function of the Redux store.

You call store.dispatch to dispatch an action. This is the only way to trigger a state change.

With React Redux, your components never access the store directly – connect does it for you. Our connected TodoList component receives props.dispatch and can dispatch actions onto itself. Hence, that’s why we give toggleTodo function to the dispatch function. Whenever we apply a state change via an action, we want this toggleTodo to be called.

we imported this function from actions:

toggleTodo return an action object with 2 properties and their data.

This action object matches up with the action parameter of a reducer function. A Reducer function will take this action object and evaluate its type.

Once, it sees that the property ‘type’ is of string ‘TOGGLE_TODO’, then it will go ahead and modify the state accordingly. In our case, it evaluates the array of strings in state, to find if the todo object’s id matches up with the id in our action object.

In other words, for every todo object, if the todo.id === action.id, then we flip the completed flag by
doing

All other properties of the todo object stays the same via

Thus, due to our TodoList component being connected to the store in VisibleTodoList.js, our reducers functions are patiently waiting for action objects to be sent from the action functions.

Once the action function fires, our reducers will receive it via its action object, and we then manipulate the state and return it.