From 3bb7309d0466b57a130fa93cd31061ce915cd568 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B8rge=20N=C3=A6ss?= Date: Wed, 29 Nov 2017 11:03:32 +0100 Subject: [PATCH] [form-builder] Memoize hot methods --- .../form-builder/src/FormBuilderContext.js | 75 ++++++++++++------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/packages/@sanity/form-builder/src/FormBuilderContext.js b/packages/@sanity/form-builder/src/FormBuilderContext.js index b7290ba1074..4ef8b479120 100644 --- a/packages/@sanity/form-builder/src/FormBuilderContext.js +++ b/packages/@sanity/form-builder/src/FormBuilderContext.js @@ -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, @@ -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