0

I'm using redux in a React application in which I use ChartJS library to make charts. I have noted that sometimes when I take an array from the global redux state, it comes like this:

 ejeY: Array(7)
    0: 43783
    1: 85001
    2: 100960
    3: 75271
    4: 22117
    5: 27542
    6: 0
    length: 7
    pop: ƒ ()
    push: ƒ ()
    shift: ƒ ()
    splice: ƒ ()
    unshift: ƒ ()
    _chartjs: {listeners: Array(1)}
    __proto__: Array(0)
    __proto__: Object

It has the array prototypes, which correspond to the methods that one can apply over an array, but outside of the Array prototype it has another methods. When the array comes like this, and I want to change the array with some method or change the state of a component using the array as value, it changes te redux state without dispatching an redux action. It's supposed that the redux props are read only, but this is changing the redux state without dispatching an action. For example, I sort two array using this method:

sortMaxToMinEjeX: (array1, array2) => {
            var list = [];
            for (var j = 0; j < array2.length; j++)
                list.push({ 'elemento1': array1[j], 'elemento2': array2[j] });
            list.sort((a, b) => {
                return ((a.elemento1 > b.elemento1) ? -1 : ((a.elemento1 === b.elemento1) ? 0 : 1));
            });
            for (var k = 0; k < list.length; k++) {
                array1[k] = list[k].elemento1;
                array2[k] = list[k].elemento2;
            }
            return { ejeY: Object.values(array2), ejeX: Object.values(array1) }
        }

And then I use the new sorted array for changing a react component props cloning the component and using the new sorted array as props:

cambiarGrafica: ({ labels, datasets }) => {
            console.log(labels, datasets);
            const { graficas, indice } = this.state;
            let nuevasGraficas = graficas.filter((componente, index) => index !== indice);
            let graficaSeleccionada;
            if (datasets) {
                graficaSeleccionada = React.cloneElement(graficas[indice], { labels, datasets });
            } else {
                graficaSeleccionada = React.cloneElement(graficas[indice], { labels });
            }
            nuevasGraficas.splice(indice, 0, graficaSeleccionada);
            this.setState({ graficas: Object.values(nuevasGraficas) });
        }

Before setting the state in the cambiarGraficas method, the redux state not change, as it should be, but when I set the state of graficas to the new array with the component with the new props, is when it changes the redux state without dispatching a action, thing that should not happen. Why is this happening and how can avoid this? Why the arrays is coming with this format?

Paul Miranda
  • 738
  • 17
  • 39

1 Answers1

3

Seems like, that you copy pointers and changing values of stuff that you didn't mean to do. When you do something like:

list.push({ 'elemento1': array1[j], 'elemento2': array2[j] });

Into the elemento1 you get the pointer of the item in the array1[j] Which means that when you later on take this list and do with it something, you basicly change the original data source of array 1.

Same happens when you use React.cloneElement. it creates a shallow copy:

"Clone and return a new React element using element as the starting point. The resulting element will have the original element’s props with the new props merged in shallowly"

https://reactjs.org/docs/react-api.html#cloneelement

For your solution, i link you here: https://medium.com/@gamshan001/javascript-deep-copy-for-array-and-object-97e3d4bc401a Where you can see the defference of deep copy and shallow copy.

At the entry of you copy function, you can use Array.from()

For array we will use ‘Array.from()’. The Array.from() method creates a new Array instance from an array-like or iterable object.

Changing the real data, with shallow copies can create lots of headache as well with redux.

Gugu
  • 193
  • 1
  • 8