Skip to content

Commit 0545e64

Browse files
committedMar 1, 2024·
feat: document the requirement for immutable changes in content (see #318)
1 parent 201f602 commit 0545e64

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed
 

‎README.md

+77
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ content: Content
224224

225225
Pass the JSON contents to be rendered in the JSONEditor. `Content` is an object containing a property `json` (a parsed JSON document) or `text` (a stringified JSON document). Only one of the two properties must be defined. You can pass both content types to the editor independent of in what mode it is. You can use two-way binding via `bind:content`.
226226

227+
> IMPORTANT: only make immutable changes to `content`. Mutable changes will mess up history and rendered contents. See section [Immutability](#immutability).
228+
227229
#### selection
228230

229231
```ts
@@ -659,6 +661,8 @@ JSONEditor.prototype.get(): Content
659661
660662
Get the current JSON document.
661663
664+
> IMPORTANT: do not mutate the received `content`, that will mess up history and rendered contents. See section [Immutability](#immutability).
665+
662666
#### set
663667
664668
```ts
@@ -675,6 +679,8 @@ JSONEditor.prototype.update(content: Content): Promise<void>
675679
676680
Update the loaded content, keeping the state of the editor (like expanded objects). You can also call `editor.updateProps({ content })`. See also method `set(content)`.
677681
682+
> IMPORTANT: only apply immutable changes to `content`. Mutable changes will mess up history and rendered contents. See section [Immutability](#immutability).
683+
678684
#### patch
679685
680686
```ts
@@ -683,6 +689,8 @@ JSONEditor.prototype.patch(operations: JSONPatchDocument) : Promise<JSONPatchRes
683689
684690
Apply a JSON patch document to update the contents of the JSON document. A JSON patch document is a list with JSON Patch operations.
685691
692+
> IMPORTANT: only apply immutable changes to the contents. Mutable changes will mess up history and rendered contents. See section [Immutability](#immutability).
693+
686694
#### updateProps
687695
688696
```ts
@@ -937,6 +945,75 @@ When updating CSS variables dynamically, it is necessary to refresh the via `edi
937945
<JSONEditor bind:this="{editorRef}" ... />
938946
```
939947
948+
## Immutability
949+
950+
It is important that the `content` of the editor is only updated in an immutable way. Mutating the `content` will break the history (undo/redo), and will not always immediately update the user interface according to the changes.
951+
952+
The reasons for requiring immutable changes are:
953+
954+
1. It is necessary in order to support history (undo/redo).
955+
2. It allows efficiently re-rendering only changed sections of the user interface.
956+
957+
Other advantages of an immutable way of working are that it makes the data that you work with much more predictive and less error-prone. You can learn more about immutability by searching for articles or videos about the subject, such as [this video](https://youtu.be/Wo0qiGPSV-s) or [this article](https://www.freecodecamp.org/news/immutability-in-javascript-with-examples/). Immutability is not _always_ the best choice, but in the case of this JSON Editor we're dealing with large and deeply nested data structures, in which we typically make only small changes like updating a single nested value. An immutable approach really shines here, enabling `svelte-jsoneditor` to smoothly render and edit JSON documents up to 512 MB.
958+
959+
Here is an example of a mutable change:
960+
961+
```js
962+
// mutable change (NOT SUPPORTED!)
963+
function updateDate() {
964+
const lastEdited = new Date().toISOString()
965+
const content = toJsonContent(myJsonEditor.get())
966+
content.json.lastEdited = lastEdited // <- this is a mutable change
967+
myJsonEditor.update(content)
968+
// ERROR: The UI will not update immediately but only update after changing something
969+
// inside the editor like the selection. And most importantly, history is broken now,
970+
// because the original document is mutated. You cannot undo this action.
971+
}
972+
```
973+
974+
Instead, you can apply the same change in an immutable way. There are various options for that:
975+
976+
```js
977+
// immutable change using a libary like "mutative" or "immer" (efficient and easy to work with)
978+
import { create } from 'mutative'
979+
function updateDate1() {
980+
const content = toJsonContent(myJsonEditor.get())
981+
const updatedContent = create(content, (draft) => {
982+
draft.json.lastEdited = new Date().toISOString()
983+
})
984+
myJsonEditor.update(updatedContent)
985+
}
986+
987+
// immutable change using "immutable-json-patch"
988+
import { setIn } from 'immutable-json-patch'
989+
function updateDate2() {
990+
const content = toJsonContent(myJsonEditor.get())
991+
const updatedContent = setIn(content, ['json', 'lastEdited'], new Date().toISOString())
992+
myJsonEditor.update(updatedContent)
993+
}
994+
995+
// immutable change using the spread operator (not handy for updates in nested data)
996+
function updateDate3() {
997+
const content = toJsonContent(myJsonEditor.get())
998+
const updatedContent = {
999+
json: {
1000+
...content.json,
1001+
lastEdited: new Date().toISOString()
1002+
}
1003+
}
1004+
myJsonEditor.update(updatedContent)
1005+
}
1006+
1007+
// immutable change by creating a deep clone (simple though inefficient)
1008+
import { cloneDeep } from 'lodash-es'
1009+
function updateDate4() {
1010+
const content = toJsonContent(myJsonEditor.get())
1011+
const updatedContent = cloneDeep(content)
1012+
updatedContent.json.lastEdited = new Date().toISOString()
1013+
myJsonEditor.update(updatedContent)
1014+
}
1015+
```
1016+
9401017
## Differences between `josdejong/svelte-jsoneditor` and `josdejong/jsoneditor`
9411018
9421019
This library [`josdejong/svelte-jsoneditor`](https://github.com/josdejong/svelte-jsoneditor/) is the successor of [`josdejong/jsoneditor`](https://github.com/josdejong/jsoneditor). The main differences are:

0 commit comments

Comments
 (0)
Please sign in to comment.