Skip to content

Commit f6e59b1

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

File tree

1 file changed

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

1 file changed

+36
-17
lines changed

Diff for: src/client/packages/idom-client-react/src/utils.js

+36-17
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,50 @@ 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+
if (!path) {
11+
// We CANNOT mutate the part of the document because React checks some
12+
// attributes of the model (e.g. model.attributes.style is checked for
13+
// identity).
14+
doc.current = applyNonMutativePatch(doc, patch, false, false, true);
15+
} else {
16+
// We CAN mutate the document here though because we know that nothing above
17+
// The patch `path` is changing. Thus, maintaining the identity for that section
18+
// of the model is accurate.
19+
applyMutativePatch(doc.current, [
20+
{
21+
op: "replace",
22+
path: path,
23+
// We CANNOT mutate the part of the document where the actual patch is being
24+
// applied. Instead we create a copy because React checks some attributes of
25+
// the model (e.g. model.attributes.style is checked for identity). The part
26+
// of the document above the `path` can be mutated though because we know it
27+
// has not changed.
28+
value: applyNonMutativePatch(
29+
jsonpatch.getValueByPointer(doc.current, path),
30+
patch
31+
),
32+
},
33+
]);
1434
}
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;
2435
forceUpdate();
2536
},
26-
[model]
37+
[doc]
2738
);
2839

29-
return [model.current, applyPatch];
40+
return [doc.current, applyPatch];
41+
}
42+
43+
function applyNonMutativePatch(doc, patch) {
44+
return jsonpatch.applyPatch(doc, patch, false, false, true).newDocument;
45+
}
46+
47+
function applyMutativePatch(doc, patch) {
48+
jsonpatch.applyPatch(doc, patch, false, true, true).newDocument;
3049
}
3150

3251
function useForceUpdate() {

0 commit comments

Comments
 (0)