Pokazywanie postów oznaczonych etykietą object. Pokaż wszystkie posty
Pokazywanie postów oznaczonych etykietą object. Pokaż wszystkie posty

poniedziałek, 19 października 2020

react i referencja

Cykl życia komponentu reacta obejmuje update komponentu, gdy dane na których pracuje komp[onent się zmienią. Dotyczy to zarówno danych przychodzacych z zewnątrz (props) jak i tych tworzonych i uaktualnianych wewnątrz komponentu (state). Jeśli chodzi o dane prymitywne (liczby, ciągi tekstowe, typy logiczne, null, undefined i Symbol) to sprawa jest dość prosta. Wiadomo, że:
console.log(1 === 1); // true
console.log('a' === 'a'); // true
console.log(true === true); // true
console.log(undefined === undefined); // true
console.log(Symbol('a').toString() === Symbol('a').toString()); // true

Czyli jeśli wartość props lub state zmieni się z 1 na 2 to komponent wie, że ma się zrerenderować. Proste.

A jednak, nie do końca. Wszystko co nie jest prymitywem w JS (jest to pewne uproszczenie, będzie osobny wpis na ten temat) jest obiektem. A obiekty nie są przekazywane przez wartość a przez referencję. Innymi słowy JS umieszcza utworzony obiekt gdzieś w pamięci i posługuje się adresem tego obiektu a nie nim samym. Każde utworzenie obiektu tworzy nową referencję.
const a = { id: 1 };
const b = { id: 1 };

console.log(a === a); // true
console.log(a === b); // false
console.log(Object.is(a, a)); // true console.log(Object.is(a, b)); // false

Czyli nawet dwa identyczne obiekty mają dwie różne referencje, więc nie da się ich łatwo porównać. React do porównywania obiektów używa Object.is().

Dlatego, gdy zmieniamy jakąś wartość w obiekcie, powinniśmy stworzyć nową referencję, żeby react zauważył zmianę, na przykład tak:
const [formData, setFormData] = useState({});

function handleChange(evt) {
  const id = evt.target.id;
  const value = evt.target.value;

  const formCopy = { ...formData };
  formCopy[id] = value;
  setFormData(formCopy);
}

Alternatywnym sposobem może być używanie biblioteki jak immutable.js aby każda zmiana w obiekcie zwracała nową referencję.

piątek, 1 lipca 2016

shallow and deep cloning objects in JavaScript

As all values in JavaScript are pass by reference clonig is quite popular operation, to save original object. Unfortunately JavaScript does not provide any method to clone deeply the whole object.

ES6 provided some features, which could be useful, but still we have to remember, that this is only a shallow cloning.

The first solution is to use Object.assign:
const a = {
  b: {
    c: 1
  },
  z: 15
};

console.log(a); // {"b":{"c":1},"z":15}

let d = Object.assign({}, a);

d.b.c = 5;
d.z = 29;

console.log(a); // {"b":{"c":5},"z":15}
console.log(d); // {"b":{"c":5},"z":29}

The first console.log will display original a object, but in the second a.b.c value will be changed. Only a.z value will stay the same. This is what shallow cloning is. Only first level properties are cloned, rest is passed by reference.

So what would happen if d.b would be changed?
d.b = 118;

console.log(a); // {"b":{"c":5},"z":15}
console.log(d); // {"b":118,"z":29}

The same situation will happen if we will use spread operator:
const aa = {
  g: {
    h: 1
  },
  y: 15
};

console.log(aa); // {"g":{"h":1},"y":15}

let e = { ...aa };

e.g.h = 9;
e.y = 23;
console.log(aa); // {"g":{"h":9},"y":15}

So, how to make a deep cloning in JavaScript?

1. Use JSON stringify and parse
JSON.parse(JSON.stringify(object));

2. Write own method to do a deep clone of passed object.