@@ -2,31 +2,67 @@ import React from "react";
2
2
import jsonpatch from "fast-json-patch" ;
3
3
4
4
export function useJsonPatchCallback ( initial ) {
5
- const model = React . useRef ( initial ) ;
5
+ const doc = React . useRef ( initial ) ;
6
6
const forceUpdate = useForceUpdate ( ) ;
7
7
8
8
const applyPatch = React . useCallback (
9
- ( pathPrefix , patch ) => {
10
- if ( pathPrefix ) {
11
- patch = patch . map ( ( op ) =>
12
- Object . assign ( { } , op , { path : pathPrefix + op . path } )
13
- ) ;
9
+ ( path , patch ) => {
10
+ let patchResult ;
11
+ if ( ! path ) {
12
+ // We CANNOT mutate the part of the document because React checks some
13
+ // attributes of the model (e.g. model.attributes.style is checked for
14
+ // identity).
15
+ patchResult = applyNonMutativePatch ( doc , patch , false , false , true ) ;
16
+ } else {
17
+ // We CAN mutate the document here though because we know that nothing above
18
+ // The patch `path` is changing. Thus, maintaining the identity for that section
19
+ // of the model is accurate.
20
+ patchResult = applyMutativePatch ( doc . current , [
21
+ {
22
+ op : "replace" ,
23
+ path : path ,
24
+ // We CANNOT mutate the part of the document where the actual patch is being
25
+ // applied. Instead we create a copy because React checks some attributes of
26
+ // the model (e.g. model.attributes.style is checked for identity). The part
27
+ // of the document above the `path` can be mutated though because we know it
28
+ // has not changed.
29
+ value : applyNonMutativePatch (
30
+ jsonpatch . getValueByPointer ( doc . current , path ) ,
31
+ patch
32
+ ) ,
33
+ } ,
34
+ ] ) ;
14
35
}
15
- // Always return a newDocument because React checks some attributes of the model
16
- // (e.g. model.attributes.style is checked for identity)
17
- model . current = jsonpatch . applyPatch (
18
- model . current ,
19
- patch ,
20
- false ,
21
- false ,
22
- true
23
- ) . newDocument ;
36
+
37
+ doc . current = patchResult . newDocument ;
24
38
forceUpdate ( ) ;
25
39
} ,
26
- [ model ]
40
+ [ doc ]
27
41
) ;
28
42
29
- return [ model . current , applyPatch ] ;
43
+ return [ doc . current , applyPatch ] ;
44
+ }
45
+
46
+ function applyNonMutativePatch ( doc , patch ) {
47
+ return jsonpatch . applyPatch (
48
+ doc ,
49
+ patch ,
50
+ false ,
51
+
52
+ false ,
53
+ true
54
+ ) . newDocument ;
55
+ }
56
+
57
+ function applyMutativePatch ( doc , patch ) {
58
+ return jsonpatch . applyPatch (
59
+ doc ,
60
+ patch ,
61
+ false ,
62
+
63
+ true ,
64
+ true
65
+ ) . newDocument ;
30
66
}
31
67
32
68
function useForceUpdate ( ) {
0 commit comments