Skip to content

Instantly share code, notes, and snippets.

Last active Nov 21, 2020
What would you like to do?
<?xml version="1.0" encoding="UTF-8"?>
<!--Xholon Workbook MIT License, Copyright (C) Ken Webb, Sat Nov 21 2020 13:39:15 GMT-0500 (Eastern Standard Time)-->
Title: immer
InternalName: 48aa9e2a6d15b79dd33f21757fcb3659
My Notes
October 30, 2020
This workbook explores immer and similar projects and ideas.
I should be able to use in with Xholon, React
To install and test
cd ~/nodespace/ OR cd ~/nodespace/node_modules ???
npm install immer
cd immer
ls -al
I should be able to use either of the following in Xholon (with size in bytes):
NO immer.cjs.development.js 57653
NO immer.cjs.production.min.js 15338
These files are in the dist directory.
I copied immer.cjs.development.js to Xholon public/lib/immer.js
I need to use the following files instead:
immer.umd.development.js 59545
immer.umd.production.min.js 15390
Simple Example [ref 6]
import produce from "immer"
const baseState = [
todo: "Learn typescript",
done: true
todo: "Try immer",
done: false
const nextState = produce(baseState, draftState => {
draftState.push({todo: "Tweet about it"})
draftState[1].done = true
Running this example in Firefox Dev Tools (it works)
const baseState = [
todo: "Learn typescript",
done: true
todo: "Try immer",
done: false
const nextState = immer.produce(baseState, draftState => {
draftState.push({todo: "Tweet about it"})
draftState[1].done = true
Create the next immutable state tree by simply modifying the current tree
Winner of the "Breakthrough of the year" React open source award and "Most impactful contribution" JavaScript open source award in 2019
JavaScript, TypeScript
Michel Westrate
Immer (German for: always) is a tiny package that allows you to work with immutable state in a more convenient way.
It is based on the copy-on-write mechanism.
The basic idea is that you will apply all your changes to a temporary draftState, which is a proxy of the currentState.
Once all your mutations are completed, Immer will produce the nextState based on the mutations to the draft state.
This means that you can interact with your data by simply modifying it while keeping all the benefits of immutable data.
Immer can be installed as a direct dependency, and will work in any ES5 environment
Yarn: yarn add immer
NPM: npm install immer
CDN: Exposed global is immer
Unpkg: <script src=""></script>
JSDelivr: <script src=""></script>
see additional details on this page
A hook to use immer as a React hook to manipulate state.
The generated patches are similar (but not the same) to the RFC-6902 JSON patch standard,
KSW this may be what I use with Xholon Meteor
basic example
How does Immer work?
Well, two words; 1) Copy-on-write. 2). Proxies. Let me draw a picture.
immer uses structural sharing
The Proxy object enables you to create a proxy for another object, which can intercept and redefine fundamental operations for that object.
Immutable JavaScript Data Structures with Immer
I did not watch this. They require creating an account.
Port of Hue Drops into React using immer
a game, TypeScript
looks like a good example
OS Awards
Tiny JS library to modify deep object properties without modifying the original object (immutability).
Works great with React (especially when using setState()) and Redux (inside a reducer).
This can be seen as a simpler and more intuitive alternative to the React Immutability Helpers and Immutable.js.
Quick usage
The following, sets a property without modifying the original object.
It will minimize the number of clones down the line.
The resulting object is just a plain JS object literal, so be warned that it will not be protected against property mutations (like Immutable.js)
const obj = {
a: {
b: 'c',
c: ['d', 'f']
const newObj = immutable.set(obj, 'a.b', 'f')
// {
// a: {
// b: 'f',
// c: ['d', 'f']
// }
// }
// obj !== newObj
// obj.a !== newObj.a
// obj.a.b !== newObj.a.b
// However:
// obj.a.c === newObj.a.c
(15) TODO
<Blockbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
// ========================================================================
// this works!
const baseState = [
todo: "Learn typescript",
done: true
todo: "Try immer",
done: false
const nextState = $wnd.immer.produce(baseState, draftState => {
draftState.push({todo: "Tweet about it"})
draftState[1].done = true
// ========================================================================
// try it with a Xholon node this partly works
// TODO it creates the new node, which refs everything just like the original base node, but it's NOT part of the Xholon tree
const xhbaseState = $wnd.xh.root().first().first();
xhbaseState[$wnd.immer.immerable] = true
const xhnextState = $wnd.immer.produce(xhbaseState, xhdraftState => {
xhdraftState["testing"] = 123
// FIXED Uncaught Error: [Immer] produce can only be called on things that are draftable: plain objects, arrays, Map, Set or classes that are marked with '[immerable]: true'. Got 'block_46'
//# sourceURL=Blockbehavior.js
<Heightbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
var myHeight, testing;
var beh = {
postConfigure: function() {
testing = Math.floor(Math.random() * 10);
myHeight = this.cnode.parent();
act: function() {
toString: function() {
return "testing:" + testing;
//# sourceURL=Heightbehavior.js
<Brickbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
$wnd.xh.Brickbehavior = function Brickbehavior() {}
$wnd.xh.Brickbehavior.prototype.postConfigure = function() {
this.brick = this.cnode.parent();
this.iam = " red brick";
$wnd.xh.Brickbehavior.prototype.act = function() {
this.brick.println("I am a" + this.iam);
//# sourceURL=Brickbehavior.js
<Brickbehavior implName="org.primordion.xholon.base.Behavior_gwtjs"><![CDATA[
console.log("I'm another brick behavior");
<SvgClient><Attribute_String roleName="svgUri"><![CDATA[data:image/svg+xml,
<svg width="100" height="50" xmlns="">
<rect id="PhysicalSystem/Block" fill="#98FB98" height="50" width="50" x="25" y="0"/>
<rect id="PhysicalSystem/Block/Height" fill="#6AB06A" height="50" width="10" x="80" y="0"/>
]]></Attribute_String><Attribute_String roleName="setup">${MODELNAME_DEFAULT},${SVGURI_DEFAULT}</Attribute_String></SvgClient>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment