# Use State Management
# Alipay mini program State Management
The original framework of Alipay mini program provides the Page/Component level data state management (this.setData()), but that is not available for Page or Component across scenarios. The general solution is to put data into globalData to solve the data sharing problem across pages.
It can be seen that basic mechanism is available for state management in the original Alipay mini program, which does not suffice the state management in complicated projects.
# Goldfish reactive State Management
On basis of the related great ideas in the community, Goldfish deposits a set of mini program friendly reactive state management framework, which enables the user to flexibly and efficiently handle the state data.
In Goldfish, state data is reactive, where the reactive data are generated with useValue(), useState(), and useComputed(). Meanwhile, the state logic module is extracted, assembled and reused on basis of function type Composition API.
# Component State Management
import { setupComponent, useState } from '@goldfishjs/core';
export interface IProps {
name: string;
}
export interface IState {
hasVisible: boolean;
}
Component(
setupComponent<IProps>(
{
// Initial default props
},
() => {
const data = useState<IState>({
hasVisible: false,
});
return {
data,
};
}
)
);
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
Direct reference is possible in the Component:
<view>{{data.hasVisible}}</view>
# Page State Management
import { setupPage, useState } from '@goldfishjs/core';
Page(
setupPage(() => {
const data = useState<{ title: string }>({
title: 'hello Goldfish',
});
return {
data,
};
}),
);
2
3
4
5
6
7
8
9
10
11
12
13
Direct reference is possible in the Page:
<view>{{data.title}}</view>
# Global State Management
# New Store
Create a new corresponding store data file in the store folder under the root directory for unified management:
// store/OrderInfo.ts
import { observable, state, computed } from '@goldfishjs/core';
@observable
export default class OrderInfo {
@state
public money?: number = 100;
@computed
public formatMoney () {
return `¥${this.money}`;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
# Register in app.js
import { setupApp } from '@goldfishjs/core';
import OrderInfo from './store/OrderInfo';
App(
setupApp(config, () => {
const data = useState<IState>({
orderInfo: new OrderInfo(),
});
return data;
}),
);
2
3
4
5
6
7
8
9
10
11
12
# Use in any Page or Component
import { useGlobalData } from '@goldfishjs/core';
import OrderInfo from './store/OrderInfo';
Page(
setupPage(() => {
// Same for the use in components
const globalData = useGlobalData();
return {
money: globalData.orderInfo.money,
};
}),
);
2
3
4
5
6
7
8
9
10
11
12
13
Direct reference is possible in the Page and Component:
<view>{{data.title}}</view>
# Change Data
To change data in the reactive system is even more simple -- just modify data directly and then all places with the data used are updated synchronously:
...
data.title = 'new title';
...
globalData.orderInfo.money = 200;
...
2
3
4
5
6
7
8
9
# Use computed & watch
In more cases when your attributes need calculation or listen, the computed
and watch
can be used. For more concepts, see Vue Computed Properties and Watchers:
Page(
setupPage(() => {
const computed = useComputed({
get shopTags() {
return data.source.map(item => item.tag);
},
});
return {
computed,
};
}),
);
2
3
4
5
6
7
8
9
10
11
12
13
<view>{{computed.shopTags}}</view>
const watch = useWatch();
watch(() => computed.shopTags, (newVal, oldVal) => {
// when computed.shopTags changed, do something
});
2
3
4
# Caution! Reactive Link Broken
While you are enjoying the convenience with reactive data, you may have to understand the reactive link broken problem. When a data is changed, the view is not updated. The link broken is simply because the top level object is overriden or a snapshot is returned.
The nature of reactive is to overwrite the getter
and setter
methods of the object. If the overwritten objects are not replaced with snapshot or the returned contents become snapshot, it is impossible to listen to the data change.
Common counterexample:
const data = useState({
a: 1,
});
const data2 = {
a: 2,
};
// Overwrite data directly
data = data2;
return {
data,
}
2
3
4
5
6
7
8
9
10
11
12
13
14
Correct example:
const data = useState({
a: 1,
});
// All operations are processed on top level
data.a = 2;
return {
data,
}
2
3
4
5
6
7
8
9
10
Common counterexample 2:
const data = useState({
a: 1,
});
return {
// Only snapshot is returned
a: data.a,
}
2
3
4
5
6
7
8
Correct example 2:
const data = useState({
a: 1,
});
return {
// Return top-level object uniformly
data,
}
2
3
4
5
6
7
8
A more complex sample:
const data = useState({
a: {
b: {},
},
});
const c = {
x: 2,
};
// reactive link broken
data.a.b.c = c;
// This will be updated
data.a.b.c.x = 3;
return {
data,
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
For the object processing, use assign
:
const data = useState({
a: {
b: {},
},
});
const c = {
x: 2,
};
// For the attribute not added to object, it is required to add again before it can be gotten via the “setter” attribute
data.a.b = {
...data.a.b,
c,
};
// Can be updated correctly
data.a.b.c.x = 3;
return {
data,
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22