mobx-loading icon indicating copy to clipboard operation
mobx-loading copied to clipboard

部署以后 key 会改变,导致取不到

Open clock157 opened this issue 4 years ago • 8 comments

image

clock157 avatar Sep 19 '19 11:09 clock157

可以提供一个在线的可复现的完整代码示例吗?

niqingyang avatar Sep 23 '19 08:09 niqingyang

@clock157 怎么操作导致 key 发生的改变,或者能详细描述一下吗?

niqingyang avatar Sep 23 '19 08:09 niqingyang

因为 models 名取自 target.constructor.name. JS 一压缩就没了.

cncolder avatar Nov 27 '19 17:11 cncolder

因为 models 名取自 target.constructor.name. JS 一压缩就没了.

正解!

niqingyang avatar Dec 01 '19 05:12 niqingyang

@niqingyang 我把你的代码复制到本地加以改造以实现更丰富的功能, 其中包含很多野路子. 目前有点忙没时间提交 patch, 因为暂时自己也理不清如何把这种设计思路解耦出来单独使用.

这里我提供一下我的思路:

前提是我采用了官方文档里联合多个 store 的建议 https://mobx.js.org/best/store.html#combining-multiple-stores

首先我把 loadingStore.actions 的类型从 { 'aStore/anAction': false } 改造成了 { aStore: { aAction: false } }

之后在 @loading 装饰器执行时不去猜测名称, 为了省事我也禁止了自定义名称. 而是把 target 对象直接向下传入 executeAction 函数.

executeAction 函数的返回值里, 我会把 target 进一步传入 loadingStore.change.

同时我会直接通过 target 找到当前 Store name 和 action name 对 loadingStore.actionsloadingStore.models 进行初始化工作, 将默认值设为 false, 这一步的工作可以避免 loading 值为 undefined 的情况.

最后在 loadingStore.change 里面我用 target 对象, 顺着 this.rootStore 找到 model name.

    Object.keys(this.rootStore).find(
      key => this.rootStore[key] instanceof target.constructor
    );

还没结束, 我们用 Mobx 的人怎么可能忍受像 Redux 一样处处是 any 的日子.

我的类定义是这样的

class LoadingStore<R = any>

我的 models 定义是这样的

models = {} as { [M in keyof R]?: boolean };

我的 actions 定义是这样的

actions = {} as {
  [M in keyof R]?: PickAsyncFunctionAsBoolean<Partial<R[M]>>
};

我的 RootStore 定义是这样的

export class RootStore {
  loadingStore: LoadingStore<RootStore>;
}

PickAsyncFunctionAsBoolean 的类型定义是这样的, 这里我只能拿到所有 async 属性, 无法判断是不是带 @loading 装饰器, 以目前的 typescript 去做这件事, 还没有靠谱的解决方案, 网上倒是真的有个疯子研究过这件事情.

type AsyncFunction = (...args: any[]) => Promise<any>;
type AsyncFunctionAsBoolean<T> = { [P in keyof T]: T[P] extends AsyncFunction ? boolean : never };
type OmitNeverValue<T> = Pick<T, { [P in keyof T]: T[P] extends never ? never : P }[keyof T]>;
/** Pick all async function field and set type to boolean. */
type PickAsyncFunctionAsBoolean<T> = OmitNeverValue<AsyncFunctionAsBoolean<T>>;

最终效果就是 loadingStore.actions.userStore?.loadProfile 是有类型提示的


executeAction 函数有个需要改进的地方就是返回 async function. 这样可以解决问题 https://github.com/niqingyang/mobx-loading/issues/3

// 以这种方式返回, 才可以被 try catch
  return async function() {
    try {
      loadingStore.change(target, propertyKey, true);
      return await func.apply(scope || this, arguments);
    } catch (err) {
      throw err;
    } finally {
      loadingStore.change(target, propertyKey, false);
    }
  };

cncolder avatar Dec 01 '19 20:12 cncolder

@niqingyang 我把你的代码复制到本地加以改造以实现更丰富的功能, 其中包含很多野路子. 目前有点忙没时间提交 patch, 因为暂时自己也理不清如何把这种设计思路解耦出来单独使用.

这里我提供一下我的思路:

前提是我采用了官方文档里联合多个 store 的建议 https://mobx.js.org/best/store.html#combining-multiple-stores

首先我把 loadingStore.actions 的类型从 { 'aStore/anAction': false } 改造成了 { aStore: { aAction: false } }

之后在 @loading 装饰器执行时不去猜测名称, 为了省事我也禁止了自定义名称. 而是把 target 对象直接向下传入 executeAction 函数.

executeAction 函数的返回值里, 我会把 target 进一步传入 loadingStore.change.

同时我会直接通过 target 找到当前 Store name 和 action name 对 loadingStore.actionsloadingStore.models 进行初始化工作, 将默认值设为 false, 这一步的工作可以避免 loading 值为 undefined 的情况.

最后在 loadingStore.change 里面我用 target 对象, 顺着 this.rootStore 找到 model name.

    Object.keys(this.rootStore).find(
      key => this.rootStore[key] instanceof target.constructor
    );

还没结束, 我们用 Mobx 的人怎么可能忍受像 Redux 一样处处是 any 的日子.

我的类定义是这样的

class LoadingStore<R = any>

我的 models 定义是这样的

models = {} as { [M in keyof R]?: boolean };

我的 actions 定义是这样的

actions = {} as {
  [M in keyof R]?: PickAsyncFunctionAsBoolean<Partial<R[M]>>
};

我的 RootStore 定义是这样的

export class RootStore {
  loadingStore: LoadingStore<RootStore>;
}

PickAsyncFunctionAsBoolean 的类型定义是这样的, 这里我只能拿到所有 async 属性, 无法判断是不是带 @loading 装饰器, 以目前的 typescript 去做这件事, 还没有靠谱的解决方案, 网上倒是真的有个疯子研究过这件事情.

type AsyncFunction = (...args: any[]) => Promise<any>;
type AsyncFunctionAsBoolean<T> = { [P in keyof T]: T[P] extends AsyncFunction ? boolean : never };
type OmitNeverValue<T> = Pick<T, { [P in keyof T]: T[P] extends never ? never : P }[keyof T]>;
/** Pick all async function field and set type to boolean. */
type PickAsyncFunctionAsBoolean<T> = OmitNeverValue<AsyncFunctionAsBoolean<T>>;

最终效果就是 loadingStore.actions.userStore?.loadProfile 是有类型提示的

executeAction 函数有个需要改进的地方就是返回 async function. 这样可以解决问题 #3

// 以这种方式返回, 才可以被 try catch
  return async function() {
    try {
      loadingStore.change(target, propertyKey, true);
      return await func.apply(scope || this, arguments);
    } catch (err) {
      throw err;
    } finally {
      loadingStore.change(target, propertyKey, false);
    }
  };

😁 思路挺好的,我目前可能没太多时间去维护这个项目,欢迎你们任意改造 ~

niqingyang avatar Dec 02 '19 01:12 niqingyang

@niqingyang 我把你的代码复制到本地加以改造以实现更丰富的功能, 其中包含很多野路子. 目前有点忙没时间提交 patch, 因为暂时自己也理不清如何把这种设计思路解耦出来单独使用.

这里我提供一下我的思路:

前提是我采用了官方文档里联合多个 store 的建议 https://mobx.js.org/best/store.html#combining-multiple-stores

首先我把 loadingStore.actions 的类型从 { 'aStore/anAction': false } 改造成了 { aStore: { aAction: false } }

之后在 @loading 装饰器执行时不去猜测名称, 为了省事我也禁止了自定义名称. 而是把 target 对象直接向下传入 executeAction 函数.

executeAction 函数的返回值里, 我会把 target 进一步传入 loadingStore.change.

同时我会直接通过 target 找到当前 Store name 和 action name 对 loadingStore.actionsloadingStore.models 进行初始化工作, 将默认值设为 false, 这一步的工作可以避免 loading 值为 undefined 的情况.

最后在 loadingStore.change 里面我用 target 对象, 顺着 this.rootStore 找到 model name.

    Object.keys(this.rootStore).find(
      key => this.rootStore[key] instanceof target.constructor
    );

还没结束, 我们用 Mobx 的人怎么可能忍受像 Redux 一样处处是 any 的日子.

我的类定义是这样的

class LoadingStore<R = any>

我的 models 定义是这样的

models = {} as { [M in keyof R]?: boolean };

我的 actions 定义是这样的

actions = {} as {
  [M in keyof R]?: PickAsyncFunctionAsBoolean<Partial<R[M]>>
};

我的 RootStore 定义是这样的

export class RootStore {
  loadingStore: LoadingStore<RootStore>;
}

PickAsyncFunctionAsBoolean 的类型定义是这样的, 这里我只能拿到所有 async 属性, 无法判断是不是带 @loading 装饰器, 以目前的 typescript 去做这件事, 还没有靠谱的解决方案, 网上倒是真的有个疯子研究过这件事情.

type AsyncFunction = (...args: any[]) => Promise<any>;
type AsyncFunctionAsBoolean<T> = { [P in keyof T]: T[P] extends AsyncFunction ? boolean : never };
type OmitNeverValue<T> = Pick<T, { [P in keyof T]: T[P] extends never ? never : P }[keyof T]>;
/** Pick all async function field and set type to boolean. */
type PickAsyncFunctionAsBoolean<T> = OmitNeverValue<AsyncFunctionAsBoolean<T>>;

最终效果就是 loadingStore.actions.userStore?.loadProfile 是有类型提示的

executeAction 函数有个需要改进的地方就是返回 async function. 这样可以解决问题 #3

// 以这种方式返回, 才可以被 try catch
  return async function() {
    try {
      loadingStore.change(target, propertyKey, true);
      return await func.apply(scope || this, arguments);
    } catch (err) {
      throw err;
    } finally {
      loadingStore.change(target, propertyKey, false);
    }
  };

@niqingyang 我把你的代码复制到本地加以改造以实现更丰富的功能, 其中包含很多野路子. 目前有点忙没时间提交 patch, 因为暂时自己也理不清如何把这种设计思路解耦出来单独使用.

这里我提供一下我的思路:

前提是我采用了官方文档里联合多个 store 的建议 https://mobx.js.org/best/store.html#combining-multiple-stores

首先我把 loadingStore.actions 的类型从 { 'aStore/anAction': false } 改造成了 { aStore: { aAction: false } }

之后在 @loading 装饰器执行时不去猜测名称, 为了省事我也禁止了自定义名称. 而是把 target 对象直接向下传入 executeAction 函数.

executeAction 函数的返回值里, 我会把 target 进一步传入 loadingStore.change.

同时我会直接通过 target 找到当前 Store name 和 action name 对 loadingStore.actionsloadingStore.models 进行初始化工作, 将默认值设为 false, 这一步的工作可以避免 loading 值为 undefined 的情况.

最后在 loadingStore.change 里面我用 target 对象, 顺着 this.rootStore 找到 model name.

    Object.keys(this.rootStore).find(
      key => this.rootStore[key] instanceof target.constructor
    );

还没结束, 我们用 Mobx 的人怎么可能忍受像 Redux 一样处处是 any 的日子.

我的类定义是这样的

class LoadingStore<R = any>

我的 models 定义是这样的

models = {} as { [M in keyof R]?: boolean };

我的 actions 定义是这样的

actions = {} as {
  [M in keyof R]?: PickAsyncFunctionAsBoolean<Partial<R[M]>>
};

我的 RootStore 定义是这样的

export class RootStore {
  loadingStore: LoadingStore<RootStore>;
}

PickAsyncFunctionAsBoolean 的类型定义是这样的, 这里我只能拿到所有 async 属性, 无法判断是不是带 @loading 装饰器, 以目前的 typescript 去做这件事, 还没有靠谱的解决方案, 网上倒是真的有个疯子研究过这件事情.

type AsyncFunction = (...args: any[]) => Promise<any>;
type AsyncFunctionAsBoolean<T> = { [P in keyof T]: T[P] extends AsyncFunction ? boolean : never };
type OmitNeverValue<T> = Pick<T, { [P in keyof T]: T[P] extends never ? never : P }[keyof T]>;
/** Pick all async function field and set type to boolean. */
type PickAsyncFunctionAsBoolean<T> = OmitNeverValue<AsyncFunctionAsBoolean<T>>;

最终效果就是 loadingStore.actions.userStore?.loadProfile 是有类型提示的

executeAction 函数有个需要改进的地方就是返回 async function. 这样可以解决问题 #3

// 以这种方式返回, 才可以被 try catch
  return async function() {
    try {
      loadingStore.change(target, propertyKey, true);
      return await func.apply(scope || this, arguments);
    } catch (err) {
      throw err;
    } finally {
      loadingStore.change(target, propertyKey, false);
    }
  };

https://github.com/webclipper/web-clipper/blob/master/src/common/loading.ts

我也自己实现了一份。API 略有不同。

DiamondYuan avatar Dec 25 '19 14:12 DiamondYuan

因为 models 名取自 target.constructor.name. JS 一压缩就没了.

正解!

这里有啥好的解决办法吗

jiaolongshenme avatar Feb 14 '22 12:02 jiaolongshenme