diff --git a/package-lock.json b/package-lock.json index 013d118..7a20d65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "clear-render", - "version": "0.1.18", + "version": "1.0.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/Comparator.js b/src/Comparator.js index 42fb293..3071e2b 100644 --- a/src/Comparator.js +++ b/src/Comparator.js @@ -1,27 +1,55 @@ class Comparator { constructor(logger) { - this._renderCount = 0; + this._logger = logger; + this._instances = {}; + } - this._prevProps = null; - this._prevState = null; + _registration(id) { + this._instances[id] = { + id, + renderCount: 0, + prevProps: null, + prevState: null, + }; + } - this._logger = logger; + _saveCall(props, state) { + const id = this._getInstanceId(props); + const instance = this._getInstance(id); + + instance.renderCount += 1; + instance.prevState = state; + instance.prevProps = props; + } + + _getInstanceId(props) { + return props.clearRenderId || null; + } + + _getInstance(id) { + return this._instances[id]; } processChanges(nextProps, nextState) { - const isFirstRender = !this._renderCount; - if (isFirstRender) { - this._logger.printInit(); + const id = this._getInstanceId(nextProps); + const instance = this._getInstance(id); + + if (!instance) { + this._registration(id); + this._logger.printInit(id); } else { - const propsChanges = this._shallowCompare(this._prevProps, nextProps); - const stateChanges = this._shallowCompare(this._prevState, nextState); + const propsChanges = this._shallowCompare(instance.prevProps, nextProps); + const stateChanges = this._shallowCompare(instance.prevState, nextState); - this._logger.printComparisonsResults(this._renderCount, propsChanges, stateChanges); + this._logger.printComparisonsResults( + id, + instance.renderCount, + propsChanges, + stateChanges + ); } - this._renderCount += 1; - this._prevState = nextState; - this._prevProps = nextProps; + this._saveCall(nextProps, nextState); } _shallowCompare(oldObj = {}, nextObj = {}) { diff --git a/src/__tests__/patch.spec.js b/src/__tests__/patch.spec.js index a763c55..1e7de5a 100644 --- a/src/__tests__/patch.spec.js +++ b/src/__tests__/patch.spec.js @@ -42,6 +42,8 @@ test('Checkbox, detect changed state', () => { expect(fakeLogger.printInit.mock.calls.length).toBe(1); expect(fakeLogger.printComparisonsResults.mock.calls.length).toBe(1); expect(fakeLogger.printComparisonsResults.mock.calls[0]).toEqual([ + null, + 1, [], [{ key: 'isChecked', nextValue: true, oldValue: false, type: 'boolean' }], ]); @@ -68,6 +70,8 @@ test('Checkbox, detect changed props', () => { expect(fakeLogger.printInit.mock.calls.length).toBe(1); expect(fakeLogger.printComparisonsResults.mock.calls.length).toBe(1); expect(fakeLogger.printComparisonsResults.mock.calls[0]).toEqual([ + null, + 1, [{ key: 'title', type: 'string', oldValue: 'ping', nextValue: 'pong' }], [], ]); @@ -75,6 +79,74 @@ test('Checkbox, detect changed props', () => { expect(getByTestId('props-title').textContent).toBe('pong'); }); +test('Checkbox, should separate instances, detect changed props', () => { + // Arrange + const fakeLogger = { + printInit: jest.fn(), + printComparisonsResults: jest.fn(), + }; + const comparator = new Comparator(fakeLogger); + const PatchedCheckbox = patch(Checkbox, comparator); + + // Act + const { rerender } = render( + + + + + ); + + rerender( + + + + + ); + + // Assert + expect(fakeLogger.printInit.mock.calls.length).toBe(2); + expect(fakeLogger.printInit.mock.calls[0]).toEqual(['1']); + expect(fakeLogger.printInit.mock.calls[1]).toEqual(['2']); + + expect(fakeLogger.printComparisonsResults.mock.calls.length).toBe(2); + expect(fakeLogger.printComparisonsResults.mock.calls[0]).toEqual([ + '1', + 1, + [ + { + key: 'title', + type: 'string', + oldValue: 'ping', + nextValue: 'pong', + }, + ], + [], + ]); + expect(fakeLogger.printComparisonsResults.mock.calls[1]).toEqual([ + '2', + 1, + [ + { + key: 'title', + type: 'string', + oldValue: 'ping', + nextValue: 'bong', + }, + ], + [], + ]); +}); + test('Counter, detect changed props re-render', () => { // Arrange const fakeLogger = { @@ -95,6 +167,8 @@ test('Counter, detect changed props re-render', () => { expect(fakeLogger.printInit.mock.calls.length).toBe(1); expect(fakeLogger.printComparisonsResults.mock.calls.length).toBe(1); expect(fakeLogger.printComparisonsResults.mock.calls[0]).toEqual([ + null, + 1, [{ key: 'title', type: 'string', oldValue: 'ping', nextValue: 'pong' }], [], ]); @@ -122,6 +196,72 @@ test('Counter, used hooks', () => { expect(fakeLogger.printComparisonsResults.mock.calls.length).toBe(1); }); +test('Counter, should separate instances, detect changed props', () => { + // Arrange + const fakeLogger = { + printInit: jest.fn(), + printComparisonsResults: jest.fn(), + }; + const comparator = new Comparator(fakeLogger); + const PatchedCounter = patch(Counter, comparator); + + // Act + const { rerender } = render( + + + + + ); + + rerender( + + + + + ); + + // Assert + expect(fakeLogger.printInit.mock.calls.length).toBe(2); + expect(fakeLogger.printComparisonsResults.mock.calls.length).toBe(2); + + expect(fakeLogger.printComparisonsResults.mock.calls[0]).toEqual([ + '1', + 1, + [ + { + key: 'title', + type: 'string', + oldValue: 'ping', + nextValue: 'pong', + }, + ], + [], + ]); + expect(fakeLogger.printComparisonsResults.mock.calls[1]).toEqual([ + '2', + 1, + [ + { + key: 'title', + type: 'string', + oldValue: 'ping', + nextValue: 'bong', + }, + ], + [], + ]); +}); + test('Input, detect changed props re-render', () => { // Arrange const fakeLogger = { @@ -147,6 +287,8 @@ test('Input, detect changed props re-render', () => { expect(fakeLogger.printInit.mock.calls.length).toBe(1); expect(fakeLogger.printComparisonsResults.mock.calls.length).toBe(1); expect(fakeLogger.printComparisonsResults.mock.calls[0]).toEqual([ + null, + 1, [{ key: 'value', type: 'string', oldValue: '', nextValue: 'i type ...' }], [], ]); diff --git a/src/logger.js b/src/logger.js index aa84f19..5283517 100644 --- a/src/logger.js +++ b/src/logger.js @@ -4,17 +4,25 @@ class Logger { this._log = log; } - printInit() { + _getComponentLabel(id) { + const componentName = this._componentName; + + if (!id) { + return componentName; + } + + return componentName + ` [id: ${id}]`; + } + + printInit(id) { + const componentLabel = this._getComponentLabel(id); + this._log.log( '%c[clear-render] init for', 'color: #848d95;', - this._componentName - ); - this._log.log( - '%c[clear-render] render', - 'color: #848d95;', - this._componentName + componentLabel ); + this._log.log('%c[clear-render] render', 'color: #848d95;', componentLabel); } _printChange(change) { @@ -39,11 +47,13 @@ class Logger { } } - printComparisonsResults(renderCount, propsChanges, stateChanges) { + printComparisonsResults(id, renderCount, propsChanges, stateChanges) { + const componentLabel = this._getComponentLabel(id); + this._log.group( `%c[clear-render] re-render #${renderCount}`, 'color: #848d95;', - this._componentName + componentLabel ); this._printComparisonResult('props', propsChanges); this._printComparisonResult('state', stateChanges); @@ -63,7 +73,6 @@ class Logger { changes.forEach(this._printChange.bind(this)); this._log.groupEnd(); } - } export default Logger;