Skip to content

Commit

Permalink
chore(vue-core): calculate getter values once (#943)
Browse files Browse the repository at this point in the history
  • Loading branch information
kvet authored Apr 18, 2018
1 parent d853f4d commit 6b6b0d2
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 8 deletions.
2 changes: 1 addition & 1 deletion packages/dx-vue-core/src/plugin-based/action.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const Action = {
position: () => this.position(),
[`${name}Action`]: (params) => {
const { action } = this;
const getters = getAvailableGetters(
const { getters } = getAvailableGetters(
pluginHost,
getterName => pluginHost.get(`${getterName}Getter`, this.plugin),
);
Expand Down
1 change: 1 addition & 0 deletions packages/dx-vue-core/src/plugin-based/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export const POSITION_CONTEXT = Symbol('position');
export const TEMPLATE_HOST_CONTEXT = Symbol('templateHost');

export const RERENDER_TEMPLATE_EVENT = Symbol('rerenderTemplate');
export const UPDATE_CONNECTION_EVENT = Symbol('updateConnection');
51 changes: 48 additions & 3 deletions packages/dx-vue-core/src/plugin-based/getter.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import {
getAvailableGetters,
isTrackedDependenciesChanged,
getAvailableActions,
} from './helpers';
import { PLUGIN_HOST_CONTEXT, POSITION_CONTEXT } from './constants';

const GLOBAL_SHIFT = 0xffff;

let globalGetterId = 0;
export const Getter = {
name: 'Getter',
props: {
Expand All @@ -21,21 +25,50 @@ export const Getter = {
pluginHost: { from: PLUGIN_HOST_CONTEXT },
position: { from: POSITION_CONTEXT },
},
created() {
this.globalId = globalGetterId;
globalGetterId += 1;
this.internalId = 0;
this.generateId();
},
beforeMount() {
const { pluginHost, name } = this;

let lastComputed;
let lastTrackedDependencies = {};
let lastResult;
let unwatch;

this.plugin = {
position: () => this.position(),
[`${name}Getter`]: (original) => {
const { value, computed } = this;
if (value !== undefined) return value;
if (computed === null) return { id: this.id, value };

const getGetterValue = getterName => ((getterName === name)
? original
: pluginHost.get(`${getterName}Getter`, this.plugin));

const getters = getAvailableGetters(pluginHost, getGetterValue);
if (computed === lastComputed &&
!isTrackedDependenciesChanged(pluginHost, lastTrackedDependencies, getGetterValue)) {
return { id: this.id, value: lastResult };
}

const { getters, trackedDependencies } = getAvailableGetters(pluginHost, getGetterValue);
const actions = getAvailableActions(pluginHost);
return computed(getters, actions);

lastComputed = computed;
lastTrackedDependencies = trackedDependencies;
if (unwatch) unwatch();
unwatch = this.$watch(
() => computed(getters, actions),
(newValue) => {
this.generateId();
lastResult = newValue;
},
{ immediate: true },
);
return { id: this.id, value: lastResult };
},
};

Expand All @@ -47,4 +80,16 @@ export const Getter = {
render() {
return null;
},
methods: {
generateId() {
this.internalId = this.internalId + 1 < GLOBAL_SHIFT ? this.internalId + 1 : 0;
// eslint-disable-next-line no-bitwise
this.id = (this.globalId << GLOBAL_SHIFT) + this.internalId;
},
},
watch: {
value() {
this.generateId();
},
},
};
53 changes: 53 additions & 0 deletions packages/dx-vue-core/src/plugin-based/getter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,4 +174,57 @@ describe('Getter', () => {
expect(wrapper.find('h1').text())
.toBe('new');
});

it('should return the same instance of the file value in several connections', () => {
const EncapsulatedPlugin = {
render() {
return (
<Plugin>
<Template name="root">
<div>
<TemplateConnector>
{({ getters: { test } }) => <h1>{test}</h1>}
</TemplateConnector>
<TemplateConnector>
{({ getters: { test } }) => <h2>{test}</h2>}
</TemplateConnector>
</div>
</Template>
</Plugin>
);
},
};

const Test = {
props: ['text'],
render() {
let counter = 0;
return (
<PluginHost>
<EncapsulatedPlugin />

<Getter
name="test"
computed={() => {
counter += 1;
return `${this.text}_${counter}`;
}}
/>
</PluginHost>
);
},
};

const wrapper = mount({
data() {
return { text: 'old' };
},
render() {
return <Test text={this.text} />;
},
});

expect(wrapper.find('h2').text())
.toBe('old_1');
});
});
30 changes: 27 additions & 3 deletions packages/dx-vue-core/src/plugin-based/helpers.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,38 @@
import { shallowEqual } from '@devexpress/dx-core';

export const getAvailableGetters = (
pluginHost,
getGetterValue = getterName => pluginHost.get(`${getterName}Getter`),
) =>
pluginHost.knownKeys('Getter')
) => {
const trackedDependencies = {};
const getters = pluginHost.knownKeys('Getter')
.reduce((acc, getterName) => {
Object.defineProperty(acc, getterName, {
get: () => getGetterValue(getterName),
get: () => {
const boxedGetter = getGetterValue(getterName);
trackedDependencies[getterName] = boxedGetter && boxedGetter.id;
return boxedGetter && boxedGetter.value;
},
});
return acc;
}, {});
return { getters, trackedDependencies };
};

export const isTrackedDependenciesChanged = (
pluginHost,
prevTrackedDependencies,
getGetterValue = getterName => pluginHost.get(`${getterName}Getter`),
) => {
const trackedDependencies = Object.keys(prevTrackedDependencies)
.reduce((acc, getterName) => {
const boxedGetter = getGetterValue(getterName);
return Object.assign(acc, {
[getterName]: boxedGetter && boxedGetter.id,
});
}, {});
return !shallowEqual(prevTrackedDependencies, trackedDependencies);
};

export const getAvailableActions = (
pluginHost,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const TemplateConnector = {
pluginHost: { from: PLUGIN_HOST_CONTEXT },
},
render() {
const getters = getAvailableGetters(this.pluginHost);
const { getters } = getAvailableGetters(this.pluginHost);
const actions = getAvailableActions(this.pluginHost);
return this.$scopedSlots.default({ getters, actions });
},
Expand Down

0 comments on commit 6b6b0d2

Please sign in to comment.