Skip to content

Commit 81cf8de

Browse files
committed
correcly apply client-side JSON patch
1 parent 57810bb commit 81cf8de

File tree

1 file changed

+53
-17
lines changed
  • src/client/packages/idom-client-react/src

1 file changed

+53
-17
lines changed

src/client/packages/idom-client-react/src/utils.js

Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,67 @@ import React from "react";
22
import jsonpatch from "fast-json-patch";
33

44
export 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

3268
function useForceUpdate() {

0 commit comments

Comments
 (0)