In this lesson we're going implement a simple counter application. Our focus will be on the stores and actions, how they interact with each other and how we can wire them up to components.
Our counter has two buttons used for incrementing and decrementing a number.
This is what it's going to look like:
components/
└── App.js
stores/
├── Store.js
└── counterStore.js
actions
└── index.js
Our directory structure looks rather boring this time, since we're mostly going to focus on the global store of our application.
Our application has a single component called <App />
. <App />
needs to be "wired" up to the counterStore
using the component's lifecycle methods:
-
componentDidMount
is going to add an event listener to thecounterStore
. If the store is being updated, the state of our<App />
component should be updated as well. -
componentWillUnmount
is going to remove the event listener.
Our <App />
component renders two buttons and the actual counter number. If we click on +
, the counter will be incremented by 1
. If we click -
, the counter will be decremented by 1
.
There are two stores: Store
and CounterStore
. CounterStore
inherits from Store
. counterStore
exports a single instance of CounterStore
, whereas Store
exports a class that we can inherit from in the future.
We first need to implement the Store
's instance methods before we can implement the CounterStore
class.
The global application state that we're updating is a simple counter, represented by a number. The initial count will be set to 0
, which will also be the initial state of the counterStore
.
There are two actions: increment()
and decrement()
. The action creators are directly wired up to the global counterStore
singleton.
increment()
and decrement()
have similar logic. They both update the counterStore
by doing the following:
- Both of them first have to retrieve the previous state using
store.getState()
. - They then add / subtract
1
from the previous state and callstore.setState(newState)
Our <App />
component doesn't directly update the store, but subscribes to its updates. The store is the single source of truth of our application, but is completely decoupled from individual components. In other words, there is no way for a component to directly update a store.
Since a counter that doesn't change its count would be rather boring, we need to figure out a way how to allow components to update the store.
E.g. if a user clicks a button, we need to change the counter (= state of the counterStore
).
Hence we add a specific set of actions that enables our components to update the store. Instead of updating the global application state in the component directly, we decouple the respective action by extracting it out from the component.
Advanced For now we're using setState
on stores to trigger a global state change. Later on we're going to introduce a dispatcher in order to introduce an isolated event bus.