Skip to content

Commit

Permalink
feat: Duplicate asyncComputed in proper, new package
Browse files Browse the repository at this point in the history
  • Loading branch information
Iku-turso committed Nov 17, 2022
1 parent bf86223 commit 5e83f5f
Show file tree
Hide file tree
Showing 10 changed files with 1,018 additions and 0 deletions.
7 changes: 7 additions & 0 deletions packages/injectable/mobx-utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# MobX utils in Ogre Tools

Utils for MobX.

## Documentation

Check unit tests for documentation.
3 changes: 3 additions & 0 deletions packages/injectable/mobx-utils/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
extends: '@ogre-tools/infrastructure-babel-for-js',
};
17 changes: 17 additions & 0 deletions packages/injectable/mobx-utils/index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { IComputedValue } from 'mobx';

export type IAsyncComputed<T> = {
value: IComputedValue<T>;
pending: IComputedValue<boolean>;
invalidate: () => void;
};

type AsyncComputedParams<T> = {
getValueFromObservedPromise: () => Promise<T>;
valueWhenPending?: T;
betweenUpdates?: 'show-pending-value' | 'show-latest-value';
};

export function asyncComputed<T>(
configuration: AsyncComputedParams<T>,
): IAsyncComputed<T>;
3 changes: 3 additions & 0 deletions packages/injectable/mobx-utils/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import asyncComputed from './src/asyncComputed/asyncComputed';

export { asyncComputed };
3 changes: 3 additions & 0 deletions packages/injectable/mobx-utils/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = require('@ogre-tools/infrastructure-jest')(
__dirname,
).configForReact;
13 changes: 13 additions & 0 deletions packages/injectable/mobx-utils/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions packages/injectable/mobx-utils/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "@ogre-tools/mobx-utils",
"private": false,
"version": "13.1.0",
"description": "A brutal component for injecting components that use injectable",
"repository": {
"type": "git",
"url": "https://github.com/ogre-works/ogre-tools"
},
"main": "build/index.js",
"types": "./index.d.ts",
"keywords": [
"js",
"functional-programming"
],
"author": "Ogre Works",
"license": "MIT",
"peerDependencies": {
"@ogre-tools/fp": "*",
"@ogre-tools/injectable": "*",
"lodash": "^4.17.21",
"mobx": "^6.3.0",
"mobx-react": "^7.2.0",
"react": "^17.0.0",
"react-dom": "^17.0.0"
},
"gitHead": "a5e3d70aa0d5d45dbf2f3d37f586fac93bfffc86",
"bugs": {
"url": "https://github.com/ogre-works/ogre-tools/issues"
},
"homepage": "https://github.com/ogre-works/ogre-tools#readme",
"publishConfig": {
"access": "public"
},
"prettier": "@ogre-tools/infrastructure-prettier",
"scripts": {
"build": "ogre-tools-build-js",
"test": "ogre-tools-test",
"code-style:verify": "ogre-tools-verify-code-style",
"code-style:fix": "ogre-tools-fix-code-style"
},
"devDependencies": {
"@ogre-tools/infrastructure-babel-for-js": "^13.1.0",
"@ogre-tools/infrastructure-jest": "^13.1.0",
"@ogre-tools/infrastructure-prettier": "^13.1.0",
"@ogre-tools/infrastructure-webpack-for-js": "^13.1.0"
}
}
93 changes: 93 additions & 0 deletions packages/injectable/mobx-utils/src/asyncComputed/asyncComputed.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { noop } from 'lodash/fp';
import { computed, createAtom, observable, runInAction, untracked } from 'mobx';

const neutralizeObsoletePromiseSymbol = Symbol.for(
'neutralize-obsolete-promise',
);

export default ({
getValueFromObservedPromise,
valueWhenPending,
betweenUpdates = 'show-pending-value',
}) => {
const invalidateAtom = createAtom('invalidate');

const pendingBox = observable.box(false);

let neutralizeObsoletePromise = noop;

const syncValueBox = observable.box(valueWhenPending, {
name: 'sync-value-box-for-async-computed',
deep: false,
});

const computedPromise = computed(
() => {
if (untracked(() => pendingBox.get()) === true) {
neutralizeObsoletePromise();
}

invalidateAtom.reportObserved();

runInAction(() => {
pendingBox.set(true);
if (betweenUpdates === 'show-pending-value') {
syncValueBox.set(valueWhenPending);
}
});

return Promise.race([
getValueFromObservedPromise(),

new Promise(resolve => {
neutralizeObsoletePromise = () =>
resolve(neutralizeObsoletePromiseSymbol);
}),
]);
},
{
name: 'computed-promise-for-async-computed',
},
);

const originalComputed = computed(
() => {
computedPromise.get().then(syncValue => {
if (syncValue !== neutralizeObsoletePromiseSymbol) {
runInAction(() => {
pendingBox.set(false);
syncValueBox.set(syncValue);
});
}
});

return syncValueBox.get();
},

{
name: 'computed-promise-result-for-async-computed',
keepAlive: true,
},
);

return {
value: originalComputed,

invalidate: () => {
runInAction(() => {
invalidateAtom.reportChanged();
pendingBox.set(true);

if (betweenUpdates === 'show-pending-value') {
syncValueBox.set(valueWhenPending);
}
});
},

pending: computed(() => {
originalComputed.get();

return pendingBox.get();
}),
};
};
Loading

0 comments on commit 5e83f5f

Please sign in to comment.