Skip to content

Commit

Permalink
Merge pull request #3544 from WordPress/fix/change-detection-multi-re…
Browse files Browse the repository at this point in the history
…duce

Framework: Fix change detection to maintain multiple instances of state
  • Loading branch information
aduth authored Nov 20, 2017
2 parents bc46f77 + 5660eb0 commit 6f5e90c
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 30 deletions.
27 changes: 10 additions & 17 deletions editor/utils/with-change-detection/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,8 @@ import { includes } from 'lodash';
* @return {Function} Enhanced reducer
*/
export default function withChangeDetection( reducer, options = {} ) {
let originalState;

return ( state, action ) => {
let nextState = reducer( state, action );
const nextState = reducer( state, action );

// Reset at:
// - Initial state
Expand All @@ -27,22 +25,17 @@ export default function withChangeDetection( reducer, options = {} ) {
includes( options.resetTypes, action.type )
);

const nextIsDirty = ! isReset && originalState !== nextState;

// Only revise state if changing.
if ( nextIsDirty !== nextState.isDirty ) {
// In case the original reducer returned the same reference and we
// intend to mutate, create a shallow clone.
if ( state === nextState ) {
nextState = { ...nextState };
}

nextState.isDirty = nextIsDirty;
if ( isReset ) {
return {
...nextState,
isDirty: false,
};
}

// Track original state against which dirty test compares reference
if ( isReset ) {
originalState = nextState;
const isChanging = state !== nextState;

if ( isChanging ) {
nextState.isDirty = true;
}

return nextState;
Expand Down
23 changes: 10 additions & 13 deletions editor/utils/with-change-detection/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import deepFreeze from 'deep-freeze';
import withChangeDetection from '../';

describe( 'withChangeDetection()', () => {
const initialState = { count: 0 };
const initialState = deepFreeze( { count: 0 } );

function originalReducer( state = initialState, action ) {
switch ( action.type ) {
Expand All @@ -18,9 +18,6 @@ describe( 'withChangeDetection()', () => {

case 'RESET_AND_CHANGE_REFERENCE':
return { ...state };

case 'SET_STATE':
return action.state;
}

return state;
Expand Down Expand Up @@ -67,19 +64,19 @@ describe( 'withChangeDetection()', () => {
expect( state ).toEqual( { count: 1, isDirty: true } );
} );

it( 'should reset if state reverts to its original reference', () => {
const reducer = withChangeDetection( originalReducer, { resetTypes: [ 'RESET' ] } );
it( 'should maintain separate states', () => {
const reducer = withChangeDetection( originalReducer );

let state;
let firstState;

const originalState = state = reducer( undefined, {} );
expect( state ).toEqual( { count: 0, isDirty: false } );
firstState = reducer( undefined, {} );
expect( firstState ).toEqual( { count: 0, isDirty: false } );

state = reducer( deepFreeze( state ), { type: 'INCREMENT' } );
expect( state ).toEqual( { count: 1, isDirty: true } );
const secondState = reducer( undefined, { type: 'INCREMENT' } );
expect( secondState ).toEqual( { count: 1, isDirty: false } );

state = reducer( deepFreeze( state ), { type: 'SET_STATE', state: originalState } );
expect( state ).toEqual( { count: 0, isDirty: false } );
firstState = reducer( deepFreeze( firstState ), {} );
expect( firstState ).toEqual( { count: 0, isDirty: false } );
} );

it( 'should flag as not dirty even if reset type causes reference change', () => {
Expand Down

0 comments on commit 6f5e90c

Please sign in to comment.