0

I am new to javascript and react (16.9.0), so I hope this question is not too obvious:

I know I can make a copy of a dictionary with '...', example: const dict_new = {...dict_old} I am using this expression to avoid a referenced copy. The problem is that when I define a dictionary inside an async componentDidMount() and make a copy of it, the copy is a referenced one despite being defined correctly. Let's me show my code:

async componentDidMount() {
      try {
        const res1 = await fetch('/postmongo/group/');
        let grupos = await res1.json();
        const res2 = await fetch('/postmongo/permiso/');
        const permisos = await res2.json();

        const dict_permisos = {};
        permisos.forEach((perm) => {
          dict_permisos[perm.descripcion] = {};
          grupos.forEach((gr) => {
            if (gr.Permisos_gemelo.some((p) => (p.nombre === perm.nombre))) {
              dict_permisos[perm.descripcion][gr.name] = true;
            } else {
              dict_permisos[perm.descripcion][gr.name] = false;
            }
          });
        });

        const dict_permisos_inicial = {...dict_permisos}

        this.setState({
          grupos,
          permisos,
          dict_permisos,
          dict_permisos_inicial,
        });

        console.log(this.state);
      } catch (e) {
        console.log(e);
      }
    }

dict_permisos_inicial is referenced copy (i.e. it is changing when dict_permisos changes) and it should be independent. What am I missing? I solved by defining the dictionary twice, maybe I should build the dictionary outside the componentDidMount(), but, where?

chococroqueta
  • 694
  • 1
  • 6
  • 18
  • You could use Object.assign to do it for you: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign – rrd Dec 12 '19 at 11:37
  • const dict_permisos_inicial = Object.assign({}, dict_permisos) Should solve the problem – Ayush Koshta Dec 12 '19 at 11:39
  • Thank you! But I am afraid it is not working, I write const dict_permisos_inicial = Object.assign({}, dict_permisos) and when compiling with Webpack, React or Webpack are automatically changing to const dict_permisos_inicial = {...dict_permisos}, as I guess they are equivalent. – chococroqueta Dec 12 '19 at 11:47

2 Answers2

0

Try Object.assign

For the most part object reset and spread work the same way, the key difference is that spread defines properties, whilst Object.assign() sets them. This means Object.assign() triggers setters.

It's worth remembering that other than this, object rest/spread 1:1 maps to Object.assign() and acts differently to array (iterable) spread. For example, when spreading an array null values are spread. However using object spread null values are silently spread to nothing.

Array (Iterable) Spread Example

const x = [1, 2, null , 3];
const y = [...x, 4, 5];
const z = null;

console.log(y); // [1, 2, null, 3, 4, 5];
console.log([...z]); // TypeError

Object Spread Example

const x = null;
const y = {a: 1, b: 2};
const z = {...x, ...y};

console.log(z); //{a: 1, b: 2}
Ayush Koshta
  • 93
  • 1
  • 10
0

Thank you all, I found the solution in this blog: https://medium.com/javascript-in-plain-english/how-to-deep-copy-objects-and-arrays-in-javascript-7c911359b089

Transcribing his words: "For objects and arrays containing other objects or arrays, copying these objects requires a deep copy. Otherwise, changes made to the nested references will change the data nested in the original object or array."

Basically, with const dict_permisos_inicial = {...dict_permisos} I am performing a shallow copy and is working perfectly fine with simple dictionaries. However, my dictionary is nested and a shallow standard copy don't work. For example:

> dict = {
...   permiso1: { grupo1: true, grupo2: false },
...   permiso2: { grupo1: false, grupo2: true }
... }
{
  permiso1: { grupo1: true, grupo2: false },
  permiso2: { grupo1: false, grupo2: true }
}
> dict_copy = {...dict}
{
  permiso1: { grupo1: true, grupo2: false },
  permiso2: { grupo1: false, grupo2: true }
}
> dict_copy["permiso1"]["grupo1"]=false
false
> dict_copy
{
  permiso1: { grupo1: false, grupo2: false },
  permiso2: { grupo1: false, grupo2: true }
}
> dict
{
  permiso1: { grupo1: false, grupo2: false },
  permiso2: { grupo1: false, grupo2: true }
}

From the solutions he shows, I used "ramda". In React:

import { clone } from 'ramda'

[some code]

const dict_permisos_inicial = clone(dict_permisos);

In Node:

> var R = require("ramda")
undefined
> dict_copy = R.clone(dict)
{
  permiso1: { grupo1: true, grupo2: false },
  permiso2: { grupo1: false, grupo2: true }
}
> dict_copy["permiso1"]["grupo1"]=false
false
> dict_copy
{
  permiso1: { grupo1: false, grupo2: false },
  permiso2: { grupo1: false, grupo2: true }
}
> dict
{
  permiso1: { grupo1: true, grupo2: false },
  permiso2: { grupo1: false, grupo2: true }
}
chococroqueta
  • 694
  • 1
  • 6
  • 18