/** * @module nextState * @private */ /** * Creates the next state tree from the current state tree and some updates. * * N.B. OO.copy doesn't copy Element instances, whereas $.extend does. * However, OO.copy does copy properties whose values are undefined or null, * whereas $.extend doesn't. Since the state tree contains an Element instance * - the preview.activeLink property - and we want to copy undefined/null into * the state we need to manually iterate over updates and check with * hasOwnProperty to copy over to the new state. * * In [change listeners](/docs/change_listener.md), for example, we talk about * the previous state and the current state (the `oldState` and `newState` * parameters, respectively). Since * [reducers](http://redux.js.org/docs/basics/Reducers.html) take the current * state and an action and make updates, "next state" seems appropriate. * * @param {Object} state * @param {Object} updates * @return {Object} */ export default function nextState( state, updates ) { const hasOwn = Object.prototype.hasOwnProperty, result = {}; // Flat clone of everything that's not updated for ( const key in state ) { if ( hasOwn.call( state, key ) && !hasOwn.call( updates, key ) ) { result[ key ] = state[ key ]; } } for ( const key in updates ) { if ( !hasOwn.call( updates, key ) ) { continue; } // Deep clone only if there is an update if ( isObject( updates[ key ] ) ) { const clone = state[ key ] ? nextState( {}, state[ key ] ) : {}; // Recursion result[ key ] = nextState( clone, updates[ key ] ); } else { result[ key ] = updates[ key ]; } } return result; } /** * @param {any} obj * @return {boolean} */ function isObject( obj ) { // https://javascript.plainenglish.io/javascript-check-if-a-variable-is-an-object-and-nothing-else-not-an-array-a-set-etc-a3987ea08fd7 return obj && obj.constructor === Object; }