Skip to content

Instantly share code, notes, and snippets.

@Isaddo
Last active June 17, 2017 13:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Isaddo/1048e61534da13529a5a15f100ca47ae to your computer and use it in GitHub Desktop.
Save Isaddo/1048e61534da13529a5a15f100ca47ae to your computer and use it in GitHub Desktop.
import memoize from 'lodash/memoize'
function isNil (value) {
return value === undefined || value === null
}
function sallowCopy (obj) {
return Array.isArray(obj) ? [...obj] : { ...obj }
}
function toUpdateFunc (input) {
return (typeof input === 'function') ? input : (() => input)
}
/**
* Creates a partial-updater function that updates a part of the value
* that `updater` will update. Updater is a function receiving a new value
* or a function returns a new value to update the value.
*
* @param {string} key The key of the value to update by the sub-updater
* @param {Function} updater The function to update a value
* @return {Function} Returns a function, only update a part of the value
*/
const splitUpdater = updater => (key, emptyObj = { }) => {
// Creates a function that updates a part of value by a newValue or
// a function recevies old obj and returns a new obj
return function partialUpdater (input, callback) {
return updater(
(obj) => Object.assign(
// Creates or clones an object for updating
isNil(obj) ? emptyObj : sallowCopy(obj),
// An object with new partial value
{ [key]: toUpdateFunc(input)(obj && obj[key]) }
),
callback
)
}
}
// cache updater with WeakMap, cache key with default Map
// when call `memoize(splitUpdater(updater))`,
// the `memoize.Cache` is `undefined`
memoize.Cache = WeakMap // prevent memory leak
const memoizedSplitUpdater = memoize(updater => memoize(splitUpdater(updater)))
memoize.Cache = undefined // reset, use default Cache for other memoized funcs
export default memoizedSplitUpdater

spliterUpdater

Usage

Split React setState for updating partial state

// in render function ...
  const update = splitUpdater(this.setState)
// ...
  <input value={value.name} onChange={update('name')}/>
  <input value={value.email} onChange={update('email')}/>
  <ItemsEditor value={value.items} onChange={update('items')}/>
// ...
// in ItemsEditor ...
  const updateItem = splitUpdater(this.props.onChange)
// ...
  props.value.forEach((item, index) => {
    const update = splitUpdater(updateItem(index))
    <input value={item.product} onChange={update('product')}/>
    <input value={item.qty} onChange={update('qty')}/>
  })
// ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment