File: README.md

package info (click to toggle)
quickflux 1.1.3%2Bgit20201110.2a37acf-4
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,036 kB
  • sloc: cpp: 2,874; makefile: 26
file content (160 lines) | stat: -rw-r--r-- 4,233 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
Todo List Example
=================

Purpose: Demonstrate how to write a QML application in a Flux way.

File Structure
--------------

```
.
├── actions
│   ├── ActionTypes.qml
│   ├── AppActions.qml
│   └── qmldir
├── adapters
├── main.qml
├── mainWindow.qml
├── middlewares
│   └── DialogMiddleware.qml
├── qml.qrc
├── stores
│   ├── MainStore.qml
│   ├── RootStore.qml
│   ├── TodoStore.qml
│   ├── UserPrefsStore.qml
│   └── qmldir
├── todo.pro
└── views
    ├── Footer.qml
    ├── Header.qml
    ├── TodoItem.qml
    ├── TodoList.qml
    └── TodoVisualModel.qml

```


**ActionTypes.qml**

ActionTypes is a constant table (singleton component) to store all the available action types.

Example:

```
pragma Singleton
import QtQuick 2.0
import QuickFlux 1.0

KeyTable {
    // KeyTable is an object with properties equal to its key name

    property string addTask;

    property string setTaskDone;

    property string setShowCompletedTasks;

}
```

It is not recommended to name an action by combing sender and event like removeItemButtonClicked.
It is suggested to tell what users do (e.g. askToRemoveItem) or what it should actually do (e.g. removeItem).
You may add a prefix of scope to its name if needed. (e.g. itemRemove)

**AppActions.qml**

AppActions is an action creator, a helper component to create and dispatch actions via the central dispatcher. It has no knowledge about the data model and who will use it. As it only depends on AppDispatcher, it could be used anywhere.

AppDispatcher is the central dispatcher. It is also a singleton object. Actions sent by dispatch() function call will be placed on a queue. Then, the Dispatcher will emit a“dispatched” signal.

Moreover, there has a side benefit in using ActionTypes and AppActions. Since they stores all the actions, when a new developer joins the project. He/she may open theses two files and know the entire API.

**Stores**

Stores contain application data, state and logic.
Somehow it is similar to MVVM's View Model.
However, Stores are read-only to Views.
Views could only query data from Stores.
"Update" should be done via Actions.
Therefore, the "queries" and "updates" operations are in fact separated.

UserPrefsStore.qml

```
import QtQuick 2.0
import QuickFlux 1.1
import "../actions"

Store {

    property bool showCompletedTasks: false

    Filter {
        // Views do not write to showCompeletedTasks directly.
        // It asks AppActions.setShowCompletedTasks() to do so.
        type: ActionTypes.setShowCompletedTasks
        onDispatched: {
            showCompletedTasks = message.value;
        }
    }

}

Design Principles
-----------------

**1. Avoid writing a big QML file. Break down into smaller pieces**

**2. Avoid signal propagation between custom view components.**

main.qml
```
Window {
    width: 480
    height: 640
    visible: true

    ColumnLayout {
        anchors.fill: parent
        anchors.leftMargin: 16
        anchors.rightMargin: 16

        Header {
            Layout.fillWidth: true
            Layout.fillHeight: false
        }

        TodoList {
            Layout.fillWidth: true
            Layout.fillHeight: true
        }

        Footer {
            Layout.fillWidth: true
            Layout.fillHeight: false
        }
    }
}
```

This example program is divided into 3 parts : Header, TodoList and Footer. 
Each part contains at least one button that may change the status to other components.
However, they are not connected by any signal/data binding between each others as shown in the above code. 
They have no knowledge of others. 
The result is a loose coupled design.

**3. Tell, Don't ask**

Inline code for handling user event can be hard to trace and test. They are not centralized in one source file. The dependence is not obvious and therefore it is easy to be broken during refactoring.

To simplify your inline code, don’t ask for the state to make any decision, just tell what do you want to do to Action class:

Example:

header.qml
```
onCheckedChanged: {
    AppActions.setTaskDone(uid,checked);
}
```