Skip to content
On this page

Patches

Structura can create a serializable list of patches with all the modifications that were applied in a producer, and can also obtain the inverse modifications to return to the original state.

Patches and inverse patches are useful for example if you want to send them over a network or to implement undo/redo functionality.

Patches do not comply with RFC 6902, so if you want to use them in another language/library you should create your own parser but you can change this by turning a setting on. Alternatively there is a converter which can turn patches generated by structura into standard JSON Patches.

Example with callback

typescript
type Make = () => Record<string, number>[]
const makeObj: Make = () => [{ A: 1 }];

// first we get the result and the patches
let patches: Patch[] = [];
let inverse: Patch[] = [];
const result = produce(
    makeObj(), 
    (draft) => {
        draft.push({ B: 2 });
    }, 
    (_patches, _inverse) => {
        patches = _patches;
        inverse = _inverse;
    }
);

// if we apply the patches from the same starting point, we get the same result
const newResult = applyPatches(makeObj(), patches);
expect(newResult).toEqual(result);

// then, if we apply the inverse patches, we obtain the original state
const undone = applyPatches(newResult, inverse);
expect(undone).toEqual(makeObj());

Example with produceWithPatches

The same example can be written more concisely by using produceWithPatches:

typescript
type Make = () => Record<string, number>[]
const makeObj: Make = () => [{ A: 1 }];

// first we get the result and the patches
const [result, patches, inverse] = produceWithPatches(makeObj(), (draft) => {
    draft.push({ B: 2 });
});

// if we apply the patches from the same starting point, we get the same result
const newResult = applyPatches(makeObj(), patches);
expect(newResult).toEqual(result);

// then, if we apply the inverse patches, we obtain the original state
const undone = applyPatches(newResult, inverse);
expect(undone).toEqual(makeObj());