管理前端应用状态
TangoBoot 采用了一个轻量级的使用 Reactive 的状态管理方案,开发者可以非常轻松的进行页面状态的管理。一个最基本的示例如下所示:
import React from 'react';
import { defineStore, definePage } from '@music163/tango-boot';
const counter = defineStore({
num: 0,
increment: () => counter.num++,
});
// 当状态变化的时候,视图会自动刷新
export default definePage(() => <button onClick={counter.increment}>{counter.num}</button>);
值得注意的是,开发者必须借助 defineStore
来定义状态,它会帮助你创建一个 observable 的状态对象。借助 definePage
来定义视图,它会帮你订一个 reactive 的视图组件,并且在自动监听状态的变化,按需进行 UI 更新。
创建状态模型 Stores
基本语法为 defineStore(storeObject: object, namespace?: string)
storeObject
为原始的状态对象namespace
为该 Store 对应的命名空间,如果你定义了,可以借助tango.stores[namespace]
来获取该引用
一个基本的例子如下:
import { defineStore } from '@music163/tango-boot';
const user = defineStore({ name: 'Rick' });
// stores behave like normal JS objects
user.name = 'Bob';
复杂的数据结构
// stores can include any valid JS structure
// including nested data, arrays, Maps, Sets, getters, setters, inheritance, ...
const user = defineStore({
profile: {
firstName: 'Bob',
lastName: 'Smith',
get name() {
return `${user.profile.firstName} ${user.profile.lastName}`;
},
},
hobbies: ['programming', 'sports'],
friends: new Map(),
});
// stores may be mutated in any syntactically valid way
user.profile.firstName = 'Bob';
delete user.profile.lastName;
user.hobbies.push('reading');
user.friends.set('id', otherUser);
异步方法
const userStore = defineStore({
user: {},
async fetchUser() {
userStore.user = await fetch('/user');
// or use this
// this.user = await fetch('/user');
},
});
多个 Store
useStore.js
import { store } from '@music163/tango-boot';
const userStore = defineStore(
{
user: {},
async fetchUser() {
userStore.user = await fetch('/user');
},
},
'userStore',
);
export default userStore;
recipesStore.js
import tango, { store } from '@music163/tango-boot';
import userStore from './userStore';
const recipesStore = defineStore(
{
recipes: [],
// 方式1:直接用调用
async fetchRecipes() {
recipesStore.recipes = await fetch(`/recipes?user=${userStore.user.id}`);
},
// 方法2:使用 this 调用,仅支持 method property,不支持箭头函数
async fetchRecipes2() {
this.recipes = await fetch(`/recipes?user=${userStore.user.id}`);
},
// 方法3:使用 tango 全局变量调用,你也可以使用这种方式引入其他的 store
async fetchRecipes3() {
tango.stores.recipesStore.recipes = await fetch(
`/recipes?user=${tango.stores.userStore.user.id}`,
);
},
},
'recipesStore',
);
export default recipesStore;
创建 Reactive 视图
你可以借助 definePage
创建视图,也可以直接包裹您的原始组件。基本用法为 definePage(Component)
,借助 definePage
可以帮你自动监听状态的变化,并在变化时自动触发视图的重新渲染。
一个简单的例子如下:
import React from 'react';
import { view, store } from '@music163/tango-boot';
// this is a global state store
const user = defineStore({ name: 'Bob' });
// this is re-rendered whenever user.name changes
export default definePage(() => (
<div>
<input value={user.name} onChange={(ev) => (user.name = ev.target.value)} />
<div>Hello {user.name}!</div>
</div>
));