Why do NgRX actions have a type

Introduction to Angular Redux - concepts and terminology

Why Redux?

State management in complex applications can quickly become a problem. Autonomous and reusable components, also called “dumb components”, communicate via and. This is absolutely correct, but every application also has components that take over our orchestration of our actual technical logic, also called “Smart Components”. Patterns such as the flux pattern are ideal for establishing the state of the entire application in a maintainable manner and according to a clear structure. Redux is the best known and most popular implementation of this pattern.

What is Redux?

Version 3 of Redux has been around for less than a year, but it has already proven to be very successful. Inspired by Flux and Elm, it is used to handle application status and effectively tie it to the user interface. Redux also enables features such as hot reloading or time travel. Redux is often used together with React, but is not tied to a specific framework.

Redux is based on flux patterns. You don't need any experience for this tutorial. We're going to cover all of the basics with this. In this article we will use a todo list example from React, taken from Dan Abramov's latest Redux video course.

Why not ngRX

Why don't we use ngRX, the standard implementation in Angular for Redux?

We want to keep this example as simple as possible. If you want to work with Redux in your Angular application, I recommend you. However, this article aims to communicate the concepts for which this simple version of Redux is more suitable. ngRx also contains extensions like, which would make the examples unnecessarily complex at this point.


Would you rather try out and discuss together?

Would you like to use Angular and Redux in your project, but you are unsure whether and how you can do it best? We deal intensively with the topic Redux with ngRX in our Angular Advanced training and work with you to develop examples that you can use directly in your project.


Introduction to Redux

Redux follows three basic principles:

  • An immutable state tree
  • Unidirectional data flow
  • Changes to the state are only made with pure functions (reducers)

With these principles we can achieve predictable and reproducible application behavior. The next diagram shows an overview of the various components of Redux, which we will now explain step by step.

Actions

These are actual actions or events in our application that potentially process the state. They can be generated by the user or the server side. They are the only source of information for the Store. Changes to the store are only initiated via actions. Actions are simple JavaScript objects that describe a change and a type Use property unique identification.

Here is an example of a very simple action:

In order to generate these action objects are also mostly Action Creators used. These are components that contain helper methods to create specific actions. These action creators help us to assemble the objects more easily and protect us from structural and typing errors.

The finished action describes what happened in our application and passes this information on to the Reducers.

Reducers

Reducers indicate how the condition is in response to a Action changes. All Reducers must be pure functions, that means:

  • They produce the same output with the same input
  • They don't produce any side effects (e.g .: mutated state, calls to the backend)

Reducers always create a new state object when changes are made in order to avoid side effects. An advanced option is to use a library like immutable.js. This means that components that access this state can use the object reference to decide whether to re-render or not. Because the state has only changed if the state is represented by a new object.

It is common practice to define these as standard parameters (line 1) and to treat each action with a switch statement.

ApplicationStore

Redux uses a single store that supports the Application state as a simple JavaScript object.

This is central to Redux and offers an API to

To-do lists example

We'll explore a todo list application to see how we can integrate Redux with Angular. This is a basic implementation where we can add new todos, mark them complete and filter them.

Application design

In Angular, we start designing our applications with one and start with a component. Below you can see a schematic pseudo-HTML with all UI components: add-todo, todo-list (Child components: todo), Filter (Chile Componenten_ filter-link).

Initialization of Redux

Initially we have to register and start Redux in our application. We do this by creating a store and registering it as a service.

Angular applications are bootstrapped in the. This declares all required components, directives and pipes. This includes the RootComponent and all the rest that are grouped in. Global dependencies are defined in the so that they are ours Redux components be available. * See and (lines 15-16).

TodoActions (class) acts as a ActionCreator with a public method for each action. We have imported dependencies (lines 2-5) and then implement (line 7) with createStore and pass the (function). Finally we used the normal Angular method with our module (line 21).

You can read more about how ngModules work at Angular Modules (angular.io)

In this simple example, we register our store using a string token. Note that we have to use @Inject (‘AppStore’) within our components when using a string token. We'll take a closer look at this in the following code examples.

Application state

The application store () keeps the application status. This is: the Todos array and the current filter.

We define the initial state as follows:

In the next section we will define the structure for a todo item. This core structure remains unchanged during the runtime of the application.

Add a new todo

Let's look at a simplified version of the AddTodo component that allows us to add a new todo and pay attention to the user input.

In the template (lines 4-8) we use a local template variable #todo (inline HTML element, line 6) and transfer its reference to the button click event (line 7). On the constructor, we injected appStore and todoActions into the component (lines 11-17) as private properties. If the user enters a description and clicks on ‘Add Todo’, an action (line 20) like the one below is given and the input content is deleted.

To avoid manually creating action objects in our components, we have the TodoActions class as one ActionCreator created.

We set that ADD_TODO Token as an action identifier (line 2). Notice how we've expanded the Action Object to include the information we need to identify todos and mark them as complete or incomplete (lines 12-15). After sending the action, the rootReducer is called by the store that has the currentState (initialState if undefined) and passes the user action.

To create the new state we use concat (to create a new array) and keep the current filters. These initially show all todos.

Toggle a todo

The user can mark each todo as completed by clicking on the place above the description. The following is a simplified marker for an active todo:

Similar to adding a todo, each click event becomes the todo ID Pass on (input attribute, line 6) and send the corresponding action (line 17).

* TypeScript Tip: The private or public modifiers in the constructor arguments are a shortcut to declare private or public objects (lines 12-13). See private / public modifiers.

Switching the first example would result in the following action:

As before, sending the action will execute the reducer and create a new state.

The helper function toggleTodo creates a new array, which switches off the todo matching of the action.id and keeps the rest.

Filter todos

The filter component enables the user to filter: all, only active or only completed todos. We use FilterLink components to encapsulate any filter that passes an identifier through the attribute filter.

Within FilterLink, every click event passes the filter (input attribute, line 6) and sends the corresponding filter action.

Filtering with Completed will generate the following action

As before, the dispatch of the action will execute the reducer and create a new state. In this case we keep the same todos and change the current filter with the supplied filter (line 5).

Display the todo list

We use a child component todo to encapsulate a single todo that passes some properties as attributes (id, closed) and the description (text) as content. This pattern is known as the Container Component.

We use ngFor to iterate over the todos array (line 3). For each todo we give the information with one local template variable To do.

In the following you can see an excerpt from the TodoList component.

  • Notice how we kept all component properties and utilities private. We don't want other components to access them. *

Redux life cycle review

Let's check how a Redux application behaves at different stages.

  • Application bootstrap: We initialize the appStore, which transfers the rootReducer. This triggers the internal commissioning of appStore. Usually this leads to intitialState
  • Component creation: We inject appStore and TodoActions on the constructor as needed. The components that display data subscribe to the appStore and read it by calling appStore.getState (). Components that mutate the state prepare the dispatch code for the appropriate action, which passes all the necessary data.
  • Component Destruction: Components displaying data, unsubscribe to the appStore to clean up resources.
  • User interactions: Each user interaction triggers a final dispatch action. This executes the RootReducer, which creates a new state. The AppStore then notifies all subscribed users, who are updated accordingly.
  • For actions initiated by the server: Some applications can send actions in response to events initiated by the server. For example: WebSockets. These properly setup actions follow the same flow as user interactions.

Phew - I have to take a closer look!

Good idea - maybe our Angular Advanced training is right for you. Here we create a sample application with ngRX together and can individually respond to your requirements in the project.


This is a translation and revision of Gerard’s great article Angular - Introduction to Redux

Use these links for the final solutions: Demo - Source