Shallow Copying JavaScript Classes

TL;DR

React's useState uses Object.is to detect state updates.

When using Array or plain Object, you can trigger updates using the spread syntax. The spread syntax provides a so-called shallow copy, and we want to use this with class instances.

The Case of Classes

The solution is the following method:

clone() {
    const clone = Object.assign({}, this);
    Object.setPrototypeOf(clone, Object.getPrototypeOf(this));
    return clone;
}

Here is a practical example:

class Entity {
	constructor(a) {
		this.a = a;
	}

	getA() {
		return this.a;
	}

	clone() {
		const clone = Object.assign({}, this);
		Object.setPrototypeOf(clone, Object.getPrototypeOf(this));
		return clone;
	}
}

const entity = new Entity(1);

// Spreading makes Object.is return false, but methods are lost
// It's just a plain object, so that's expected
const o = { ...entity };
Object.is(o, entity);
// false

o.getA();
// Uncaught TypeError: o.getA is not a function

// Using clone preserves the methods
const entity_clone = entity.clone();

Object.is(entity_clone, entity);
// false

entity_clone.getA();
// 1

Reference

Create an issue on GitHub about this article

Read Next