OhBizzle OhBizzle - 20 days ago 6
React JSX Question

Data From Import Changing

I'm new to React / ES6 and this could be a basic issue. I'm creating a .js file that exports an array of json files. This data is not supposed to change, later when I click a "clear" button, I want to reset my data to the original data from this file. For some reason the data replacements I make to my state, are changing the original import. Any help would be much appreciated. I'm pretty sure I don't need Immutable.js in this scenario but i'm currently using it in hopes to remove this issue, so far it has not worked.

TimerData

const nelths = {
level: 10,
endTime: 1980,
objectives: [
{
id: 1,
objectiveName: "Rokmora",
objectiveCompleteTime: null
},
{
id: 2,
objectiveName: "Ularogg Cragshaper",
objectiveCompleteTime: null
},
{
id: 3,
objectiveName: "Naraxas",
objectiveCompleteTime: null
},
{
id: 4,
objectiveName: "Dargrul",
objectiveCompleteTime: null
},
],
}
const TimerData = [nelths];
export default TimerData;


Imports

import React, { Component } from 'react'
import TimerData from './timerData'
import FontAwesome from 'react-fontawesome'
import {Map} from 'immutable'


Constructor

constructor(props) {
super(props);
//const timerData = Object.assign({}, TimerData[0]);
var timerData = Map(TimerData[0]);
this.state = {
level: timerData.get('level'),
endTime: timerData.get('endTime'),
objectives: timerData.get('objectives'),
}
}


Modification

var objs = this.state.objectives.slice();
objs.forEach(function (element, index, array) {
element.objectiveCompleteTime = Date.now();
});
this.setState(Object.assign({}, this.state, {objectives: objs}));


Clear

var timerData = Map(TimerData[0]);
this.setState(Object.assign({}, this.state, {objectives: timerData.get('objectives'), active: false}));


I have cut out some of the code to try and save space and show the core components of my state init & modifications. Along with any hints about the issue and tips about bad practices would be appreciated.

Thank you for your time!

Answer

Using Immutable.Map doesn't make the values of the Map immutable. You might want to look into using Immutable.fromJS:

As you can see below, the Map's values are references to the values of the object passed to the constructor.

const { Map } = Immutable;

const parent = { child: [] };
console.log('Initial parent.child =', parent.child);

const map = Map(parent);
const mapChild = map.get('child');

console.log('mapChild === parent.child:', mapChild === parent.child);

mapChild.push(1);
console.log('After pushing 1 to mapChild, parent.child =', parent.child);
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>

const { fromJS } = Immutable;
const timerData = {
  level: 10,
  endTime: 1980,
  objectives: [
    {
      id: 1,
      objectiveName: "Rokmora",
      objectiveCompleteTime: null
    },
    {
      id: 2,
      objectiveName: "Ularogg Cragshaper",
      objectiveCompleteTime: null
    },
    {
      id: 3,
      objectiveName: "Naraxas",
      objectiveCompleteTime: null
    },
    {
      id: 4,
      objectiveName: "Dargrul",
      objectiveCompleteTime: null
    },
  ],
};
    
const data = fromJS(timerData);
    
const updatedData = data.update('objectives', objective => (
  objective.map(value => value.set('objectiveCompleteTime', Date.now()))
));
    
console.log('AFTER - updatedData:', updatedData);
console.log('AFTER - data:', data);
console.log('AFTER - timerData:', timerData);
<script src="https://cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable.js"></script>

Depending on what you are looking to do, ImmutableJs might not be needed. You could deep clone the reference object: How to Deep clone in javascript

For your current object, JSON.parse and JSON.stringify would create a deep clone

const nelths = {
  level: 10,
  endTime: 1980,
  objectives: [
    {
      id: 1,
      objectiveName: "Rokmora",
      objectiveCompleteTime: null
    },
    {
      id: 2,
      objectiveName: "Ularogg Cragshaper",
      objectiveCompleteTime: null
    },
    {
      id: 3,
      objectiveName: "Naraxas",
      objectiveCompleteTime: null
    },
    {
      id: 4,
      objectiveName: "Dargrul",
      objectiveCompleteTime: null
    },
  ],
}
    
const cloned = JSON.parse(JSON.stringify(nelths));
console.log(cloned);

cloned.objectives.forEach(objective => (
  objective.objectiveCompleteTime = Date.now()
));

console.log('AFTER');
console.log('cloned', cloned);
console.log('original', nelths);

Comments