Updating Data

State Management

On every render, KronoGraph must decide whether any of its props have changed and what to update accordingly. KronoGraph must decide if any data has changed every time the API is called, and make the respective updates. The timeline assumes that whenever a new object is passed into a prop, property, something has changed and KronoGraph will redraw. If the same object is passed into a prop, set(), it assumes nothing has changed, even if the object itself has been altered.

By relying on referential equality to detect changes, KronoGraph can quickly and efficiently respond to re-renders, even in very large datasets.

This means that applications must be disciplined in how state is updated to prevent unnecessary redraws being called. For example, passing a new object with identical property values into the entities prop property will trigger the data to be reloaded and redrawn.

This holds true across the state tree: if a sub property has changed, a whole new object hierarchy must be created and passed into the relevant prop. property. Consider the following object in the entities prop: property:

const entities = {
  'smith-j' : {
    label: 'John Smith',
    fontIcon: {
      text: '☺',
    },
  },
};

To change John Smith's fontIcon.text property, we can't simply mutate the first object and pass the same into the entities prop, property, as the change will not be recognized and our timeline will stay the same.

To correctly render this change, we have to create new objects for entities, smith-j (i.e. entities['smith-j']), and fontIcon. We also need to create a new parent object to pass to set(). In the object below, we've starred the properties that need to be re-created:

const entities* = {
  'smith-j'* : {
    label: 'John Smith',
    fontIcon*: {
      text: '☺',
    },
  },
};

In a real app, we would have something like:

// Clone the entities object before making any changes
const newEntities = Object.assign({}, this.state.entities);

// Clone and update the entity we want to change
const newEntity = Object.assign({}, newEntities['smith-j'], {
  fontIcon: {
    ...newEntities['smith-j'].fontIcon,
    text: '$',
  }
});

// Write the change back to the newEntities object
newEntities['smith-j'] = newEntity;

// Update app state and trigger a re-render
this.setState({ entities: newEntities });
// In this example, we assume that the app has a 'let currentData'
// variable containing an object with properties
// 'entities', 'events', 'entityTypes' and 'eventTypes'.

// Clone the entities object before making any changes
const newEntities = Object.assign({}, currentData.entities);

// Clone and update the entity we want to change
const newEntity = Object.assign({}, newEntities['smith-j'], {
  fontIcon: {
    ...newEntities['smith-j'].fontIcon,
    text: '$',
  }
});

// Write the change back to newEntities
newEntities['smith-j'] = newEntity;

// Update the app's currentData object with the changed
// entities object and pass the new object to the timeline.
currentData = { ...currentData, entities: newEntities }
timeline.set(currentData);

For an example of passing state changes in and out of the Timeline component, see the Change Event story.

Using immutability in your app's code provides better performance, fewer unexpected side-effects, and allows you to rewind or undo user actions.

There are many code patterns and functions designed for immutability, including:

  • Object.assign()
  • The spread operator const events = {...this.state.events}; const events = { ...state.events };
  • Array operators like map and filter
  • Utility libraries like lodash

We use these patterns throughout our stories.

Terms of use

These terms do not alter or supersede any existing agreements between you (or your employer) and us.

By accessing or using any Content you agree to be bound by these Terms of Use. Please review these terms carefully before using the website.

The contents of this website, including but not limited to any text, code samples, API references, schemas, interactive tools, and other materials (collectively, the 'Content'), are made available for informational and internal evaluation purposes only. All intellectual property rights in the Content are reserved. No licence is granted to use the Content for any commercial purpose, or to copy, distribute, modify, reverse-engineer, or incorporate any part of the Content into any product or service, without our prior written consent.

This Content is provided “as is” and “as available,” without any representations, warranties, or guarantees of any kind, whether express or implied, including but not limited to implied warranties of merchantability, fitness for a particular purpose, non-infringement, or accuracy. To the fullest extent permitted by applicable law, we expressly exclude and disclaim all implied warranties, conditions, and other terms that might otherwise be implied.

We disclaim all liability for any loss or damage, whether direct, indirect, incidental, consequential, or otherwise, arising from any reliance placed on the Content or from your use of it, to the fullest extent permitted by applicable law. By continuing to access or use the Content, you acknowledge and agree to these terms.