@@ -2,31 +2,67 @@ import React from "react";
22import jsonpatch from "fast-json-patch" ;
33
44export function useJsonPatchCallback ( initial ) {
5- const model = React . useRef ( initial ) ;
5+ const doc = React . useRef ( initial ) ;
66 const forceUpdate = useForceUpdate ( ) ;
77
88 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+ ] ) ;
1435 }
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 ;
2438 forceUpdate ( ) ;
2539 } ,
26- [ model ]
40+ [ doc ]
2741 ) ;
2842
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 ;
3066}
3167
3268function useForceUpdate ( ) {
0 commit comments