Skip to content

Commit

Permalink
[form-builder] Memoize hot methods (#395)
Browse files Browse the repository at this point in the history
  • Loading branch information
bjoerge committed Nov 29, 2017
1 parent 65ec018 commit 3c55877
Showing 1 changed file with 48 additions and 27 deletions.
75 changes: 48 additions & 27 deletions packages/@sanity/form-builder/src/FormBuilderContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,40 @@ function resolve(type, providedResolve = NOOP) {
return undefined
}

// Memoize return values from a method that takes a single arg
// memoized as a map of argument => return value
function memoizeMap(method) {
const map = new WeakMap()
return function memoizedMap(arg) {
if (map.has(arg)) {
return map.get(arg)
}
const val = method.call(this, arg)
map.set(arg, val)
return val
}
}

// Memoize return value from method that takes no args
function memoize(method) {
let called = false
let val
return function memoized() {
if (called) {
return val
}
val = method.call(this)
called = true
return val
}
}

export default class FormBuilderContext extends React.Component {
static createPatchChannel = () => {
const channel = pubsub()
return {onPatch: channel.subscribe, receivePatches: channel.publish}
}

static propTypes = {
schema: PropTypes.instanceOf(Schema).isRequired,
value: PropTypes.any,
Expand All @@ -49,41 +78,33 @@ export default class FormBuilderContext extends React.Component {
return this.props.value
}

resolveInputComponent = type => {
resolveInputComponent = memoizeMap(type => {
const {resolveInputComponent} = this.props
return resolve(type, resolveInputComponent) || fallbackInputs[type.jsonType]
}
})

resolvePreviewComponent = type => {
resolvePreviewComponent = memoizeMap(type => {
const {resolvePreviewComponent} = this.props

return resolve(type, resolvePreviewComponent)
}
})

_getMemoizedChildContext() {
if (!this._childContext) {
const {schema, patchChannel} = this.props
this._childContext = {
getValuePath: () => ([]),
formBuilder: {
onPatch: patchChannel ? patchChannel.onPatch : () => {
// eslint-disable-next-line no-console
console.warn('No patch channel provided to form-builder. If you need input based patch updates, please provide one')
return NOOP
},
schema,
resolveInputComponent: this.resolveInputComponent,
resolvePreviewComponent: this.resolvePreviewComponent,
getDocument: this.getDocument
}
getChildContext = memoize(() => {
const {schema, patchChannel} = this.props
return {
getValuePath: () => ([]),
formBuilder: {
onPatch: patchChannel ? patchChannel.onPatch : () => {
// eslint-disable-next-line no-console
console.warn('No patch channel provided to form-builder. If you need input based patch updates, please provide one')
return NOOP
},
schema,
resolveInputComponent: this.resolveInputComponent,
resolvePreviewComponent: this.resolvePreviewComponent,
getDocument: this.getDocument
}
}
return this._childContext
}

getChildContext() {
return this._getMemoizedChildContext()
}
})

render() {
return this.props.children
Expand Down

0 comments on commit 3c55877

Please sign in to comment.