From c320d2364ed4c3c24ca3163f535e1090d4968601 Mon Sep 17 00:00:00 2001 From: Kenichi Kobayashi Date: Wed, 8 Jun 2022 18:33:53 +0900 Subject: [PATCH] Performance: suppresses redundant SideBar re-rendering on state.tags (#6451) --- packages/lib/reducer.test.js | 22 ++++++++++++++++++++++ packages/lib/reducer.ts | 7 +++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/lib/reducer.test.js b/packages/lib/reducer.test.js index 1e9d9b7a6..85b6b5326 100644 --- a/packages/lib/reducer.test.js +++ b/packages/lib/reducer.test.js @@ -610,4 +610,26 @@ describe('reducer', function() { expect(state.selectedNoteIds).toBe(expected); } }); + + // tests for TAG_UPDATE_ALL about PR #6451 + it('should not change tags when a new value is deep equal to the old value', async () => { + const tags = await createNTestTags(6); + const oldTags = tags.slice(0, 5); + { + // Case 1. The input which is deep equal to the current state.tags doesn't change state.tags. + const oldState = initTestState(null, null, null, null, oldTags, [2]); + const newTags = oldTags.slice(); + // test action + const newState = reducer(oldState, { type: 'TAG_UPDATE_ALL', items: newTags }); + expect(newState.tags).toBe(oldState.tags); + } + { + // Case 2. A different input changes state.tags. + const oldState = initTestState(null, null, null, null, oldTags, [2]); + const newTags = oldTags.slice().splice(3, 1, tags[5]); + // test action + const newState = reducer(oldState, { type: 'TAG_UPDATE_ALL', items: newTags }); + expect(newState.tags).not.toBe(oldState.tags); + } + }); }); diff --git a/packages/lib/reducer.ts b/packages/lib/reducer.ts index 9314fe2c8..58b9b533b 100644 --- a/packages/lib/reducer.ts +++ b/packages/lib/reducer.ts @@ -1,4 +1,4 @@ -import produce, { Draft } from 'immer'; +import produce, { Draft, original } from 'immer'; import pluginServiceReducer, { stateRootKey as pluginServiceStateRootKey, defaultState as pluginServiceDefaultState, State as PluginServiceState } from './services/plugins/reducer'; import shareServiceReducer, { stateRootKey as shareServiceStateRootKey, defaultState as shareServiceDefaultState, State as ShareServiceState } from './services/share/reducer'; import Note from './models/Note'; @@ -7,6 +7,7 @@ import BaseModel from './BaseModel'; import { Store } from 'redux'; import { ProfileConfig } from './services/profileConfig/types'; import * as ArrayUtils from './ArrayUtils'; +const fastDeepEqual = require('fast-deep-equal'); const { ALL_NOTES_FILTER_ID } = require('./reserved-ids'); const { createSelectorCreator, defaultMemoize } = require('reselect'); const { createCachedSelector } = require('re-reselect'); @@ -924,7 +925,9 @@ const reducer = produce((draft: Draft = defaultState, action: any) => { break; case 'TAG_UPDATE_ALL': - draft.tags = action.items; + if (!fastDeepEqual(original(draft.tags), action.items)) { + draft.tags = action.items; + } break; case 'TAG_SELECT':