我正在处理一个页面,用于编辑分配给员工的任务,这些任务具有薪水和权限。
页面状态数据的形状如下:
TaskObject {
Model : Object, // where the actual data of the TaskObject is stored
PermissionLinks : PermissionLink[],
Payrates : PayRate[],
OriginalObject : TaskObject
}
在整个任务本身,薪资小部件和权限链接页面上,页面上可能发生的动作如此之多,以至于我决定将商店as is described here进行拆分,如下所示:< / p>
TasksStore
/**
* @class
* The state of the entire tasks page
*/
class TasksStore {
/**
* @field {TaskObject[]}
*/
tasks = [];
taskIndex = -1;
// child stores
payRatesStore;
permissionLinksStore;
// this is part of what was done here: https://mobx.js.org/refguide/computed-decorator.html#computeds-with-arguments
_tasksCache = new Map();
_taskIndexCache = new Map();
constructor() {
// initialize the stores in the constructor
this.payRatesStore = new PayRatesStore(this);
this.permissionLinksStore = new PermissionsStore(this);
mobx.autorun(() => {
console.log('this.tasks === ', this.tasks);
})
}
// getters
get tasksHaveChanged() {
return this.tasks.reduce((prevTask, currentTask) => {
return ((prevTask.IsChanged()) && (currentTask.IsChanged()))
})
}
/**
* @return {TaskObject} the current task
*/
get currentTask() {
if ((!this.tasks) || (this.taskIndex === -1)) {
return null
}
return this.tasks[this.taskIndex]
}
// TODO: Should we, and if so, how, to mark this method computed (Mobx cannot mark arg-taking functions as @computed)
/**
* Returns the index of task with respect to this list of tasks
* @param {TaskObject} task
*/
indexOf(task) {
// Implementation for this is inspired by https://mobx.js.org/refguide/computed-decorator.html#computeds-with-arguments
const id = task.Model.Id
if (this._taskIndexCache.has(id)) {
return this._taskIndexCache.get(id).get()
}
const computedFind = computed(() => this.tasks.find((val) => (JSON.stringify(val) === JSON.stringify(task))))
this._taskIndexCache.set(id, computedFind)
return computedFind.get()
}
/**
* Returns the index of task with respect to this list of tasks
* @param {TaskObject} task
* @return {TaskObject} the task, if found, or undefined
*/
find(task) {
// Implementation for this is inspired by https://mobx.js.org/refguide/computed-decorator.html#computeds-with-arguments
const id = task.Model.Id
if (this._tasksCache.has(id)) {
return this._tasksCache.get(id).get()
}
const computedFind = computed(() => this.tasks.find((val) => (JSON.stringify(val) === JSON.stringify(task))))
this._tasksCache.set(id, computedFind)
return computedFind.get()
}
// actions
/**
* Adds a task
* @param {TaskObject} task
*/
addTask(task) {
this.tasks.push(Object.assign(task, { _added : true }));
}
/**
* Removes a task
* @param {TaskObject} task
*/
removeTask(task) {
// find the task
let foundTask = this.find(task)
if (foundTask) {
// if the task there is _added
if (foundTask._added) {
// splice it out
this.tasks.splice(taskIndex, 1)
}
// otherwise, mark it _deleted
else {
task._deleted = true
}
}
}
revertTaskChanges(task) {
// find the task
let foundTask = this.find(task)
if (foundTask) {
// revert back to state of OriginalObject
Object.assign(foundTask, foundTask.OriginalObject)
}
}
}
/* decorating the class; // have to do it this way because decorator syntax is in ES.next, which hasn't released yet. Also, I cannot seem to get it via Babel CDN link */
mobx.decorate(TasksStore, {
tasks : mobx.observable,
taskIndex : mobx.observable,
tasksHaveChanged : mobx.computed,
currentTask : mobx.computed,
addTask : mobx.action,
removeTask : mobx.action,
setPermissionLinks : mobx.action,
revertTaskChanges : mobx.action,
saveTasks : mobx.action
})
PayRatesStore
/**
* @class
* The state of the pay rates
*/
class PayRatesStore {
/**
* @field {PayRate[]}
*/
payRates = []
payRateIndex = -1;
_payRatesCache = new Map();
/**
* @param {TasksStore} tasksStore
*/
constructor(tasksStore) {
this.tasksStore = tasksStore
}
// getters
get currentPayRate() {
return this.payRates[this.payRateIndex];
}
set currentPayRate(newPayRate) {
this.payRates[this.payRateIndex] = newPayRate;
}
/**
* Returns the index of payRate with respect to this list of PayRates
* @param {PayRate} payRate
* @return {PayRate} the payRate, if found, or undefined
*/
find(payRate) {
const stringID = `storeID:${payRate.StoreId};empID:${payRate.EmpId};taskID:${payRate.TaskId}`
// Implementation for this is inspired by https://mobx.js.org/refguide/computed-decorator.html#computeds-with-arguments
if (this._payRatesCache.has(stringID)) {
return this._payRatesCache.get(stringID).get()
}
const computedFind = computed(() => this.payRates.find((val) => (JSON.stringify(val) === JSON.stringify(payRate))))
this._payRatesCache.set(stringID, computedFind)
return computedFind.get()
}
// actions
/**
* Adds a PayRate
* @param {PayRate} payRate
*/
addPayRate(payRate) {
this.payRates.push(Object.assign(payRate, { _added : true }))
}
/**
* Edits the current PayRate
* @param {PayRate} payRate
* @deprecated This may not be necessary. Just update the PayRate from the caller!
*/
editPayRate(payRate) {
this.currentPayRate = payRate
}
/**
* Removes a payRate at index
* @param {number} index
*/
removePayRateAt(index) {
// if this payrate has been _added, actually remove it
let foundPayRate = this.payRates[index]
if (foundPayRate._added) {
this.payRates.splice(index, 1)
}
// otherwise, mark it deleted
else {
foundPayRate._deleted = true
}
}
/**
* Undo removal of PayRate
* @param {number} index
*/
undoRemovePayRateAt(index) {
// if it is marked _deleted, revert that
let foundPayRate = this.payRates[index]
if (foundPayRate._deleted) {
delete foundPayRate._deleted
}
}
}
mobx.decorate(PayRatesStore, {
payRates : mobx.observable,
payRateIndex : mobx.observable,
currentPayRate : mobx.computed,
addPayRate : mobx.action,
editPayRate : mobx.action,
removePayRateAt : mobx.action,
undoRemovePayRateAt : mobx.action
})
PermissionsStore
/**
* @class
* The state of the permissions part of the Tasks page
*/
class PermissionsStore {
permissionLinkList = [];
/**
* @param {TasksStore} tasksStore
*/
constructor(tasksStore) {
this.tasksStore = tasksStore
}
get permissionLinks() {
return this.permissionLinkList;
}
/**
* Sets this store's permission links
* @param {PermissionLink[]} permissionLinks
*/
set permissionLinks(permissionLinks) {
this.permissionLinkList = permissionLinks;
}
}
mobx.decorate(PermissionsStore, {
permissionLinks : mobx.computed
})
问题
当我尝试在控制台上使用时:
tasksStore =新的TasksStore() newTask = new TaskObject(...)//一些虚拟任务或一些刮擦任务 taskStore.add(newTask)
我注意到this.tasks === ...
仅打印一次!更糟糕的是:薪资和权限存储无法从添加的任务中获取数据!
如何真正链接子商店?