diff --git a/src/App.svelte b/src/App.svelte index 625bbb5..c95d4f3 100644 --- a/src/App.svelte +++ b/src/App.svelte @@ -7,7 +7,7 @@ export let searchText = '' - let json = { + export let json = { 'array': [1, 2, 3, { name: 'Item ' + 2, id: String(2), @@ -102,7 +102,7 @@ } function handleChangeValue (value, key) { - console.log('App handleChangeValue') + console.log('App handleChangeValue', value, key) json = value } diff --git a/src/JSONNode.svelte b/src/JSONNode.svelte index 280d9ab..0372d1c 100644 --- a/src/JSONNode.svelte +++ b/src/JSONNode.svelte @@ -5,7 +5,7 @@ import classnames from 'classnames' import { isUrl, stringConvert, valueType } from './utils/typeUtils' import { escapeHTML } from './utils/stringUtils.js' - import { createUpdateProps } from './utils/updateProps.js' + import { updateProps } from './utils/updateProps.js' import { unescapeHTML } from './utils/stringUtils' export let key = undefined @@ -18,19 +18,18 @@ const DEFAULT_LIMIT = 100 const escapeUnicode = false // TODO: pass via options - // create lazy, memoized updateProps function - let updateProps = function lazyUpdateProps (value) { - updateProps = createUpdateProps() - return updateProps(value) - } - let limit = DEFAULT_LIMIT $: type = valueType (value) - $: props = type === 'object' - ? updateProps(value) - : undefined + let prevValue = undefined + let props = updateProps(value) + + $: if (value !== prevValue) { + prevValue = value + + props = updateProps(value, props) + } $: limited = type === 'array' && value.length > limit @@ -96,8 +95,15 @@ const index = props.findIndex(item => item.key === oldChildKey) if (index !== -1) { - // FIXME: make immutable (not possible as long as prevProps is stored in updateProps - props[index].key = newChildKey + // we use splice here to replace the old key with the new new one + // already without Svelte noticing it (no assignment), so we prevent + // a needless render. We keep the same id, so the child HTML will be + // reused + // TODO: is there a better way to do this? + props.splice(index, 1, { + id: props[index].id, + key: newChildKey + }) } onChangeValue(updatedValue, key) diff --git a/src/utils/updateProps.js b/src/utils/updateProps.js index 7621873..37f5d41 100644 --- a/src/utils/updateProps.js +++ b/src/utils/updateProps.js @@ -1,34 +1,26 @@ import { isObject } from './typeUtils.js' import uniqueId from 'lodash/uniqueId.js' -export function createUpdateProps () { - let prevProps = undefined +export function updateProps (value, prevProps) { + if (isObject(value)) { + // copy the props that still exist + const props = prevProps + ? prevProps.filter(item => value[item.key] !== undefined) + : [] - return function updateProps (value) { - // TODO: optimize. check if value is the same as prevValue, if so, don't do anything + // add new props + const prevKeys = new Set(props.map(item => item.key)) + Object.keys(value).forEach(key => { + if (!prevKeys.has(key)) { + props.push({ + id: uniqueId(), + key + }) + } + }) - if (isObject(value)) { - const props = prevProps - ? prevProps.filter(item => value[item.key] !== undefined) // copy the props that still exist - : [] - - // process added props - const prevKeys = new Set(props.map(item => item.key)) // TODO: this is inefficient, creating a set. cache this set? - - Object.keys(value).forEach(key => { - if (!prevKeys.has(key)) { - props.push({ - id: uniqueId(), - key - }) - } - }) - - prevProps = props - return props - } else { - prevProps = undefined - return undefined - } + return props + } else { + return undefined } }