client/state/utils.js
function serializeState( reducers, state, action ) {
	if ( state === undefined ) {
		return undefined;
	}

	return reduce(
		reducers,
		( result, reducer, reducerKey ) => {
			const serialized = reducer( state[ reducerKey ], action );
			if ( serialized !== undefined ) {
				if ( ! result ) {
					// instantiate the result object only when it's going to have at least one property
					result = new SerializationResult();
				}
				if ( reducer.storageKey ) {
					result.addKeyResult( reducer.storageKey, serialized );
				} else {
					result.addRootResult( reducerKey, serialized );
				}
			}
			return result;
		},
		undefined
	);
}
function serializeState( reducers, state, action ) {
	if ( state === undefined ) {
		return undefined;
	}

	return reduce(
		reducers,
		( result, reducer, reducerKey ) => {
			const serialized = reducer( state[ reducerKey ], action );
			if ( serialized !== undefined ) {
				if ( ! result ) {
					// instantiate the result object only when it's going to have at least one property
					result = new SerializationResult();
				}
				if ( reducer.storageKey ) {
					result.addKeyResult( reducer.storageKey, serialized );
				} else {
					result.addRootResult( reducerKey, serialized );
				}
			}
			return result;
		},
		undefined
	);
}
SERIALIZE needs behavior that's slightly different from `combineReducers` from Redux: - `undefined` is a valid value returned from SERIALIZE reducer, but `combineReducers` would throw an exception when seeing it. - if a particular subreducer returns `undefined`, then that property won't be included in the result object at all. - if none of the subreducers produced anything to persist, the combined result will be `undefined` rather than an empty object. - if the state to serialize is `undefined` (happens when some key in state is missing) the serialized value is `undefined` and there's no need to reduce anything.