diff --git a/conda/js/src/components/toolchain/ToolchainEditor.jsx b/conda/js/src/components/toolchain/ToolchainEditor.jsx
index af52d038ce5156ca442bdbc8ba00ca1494f765ee..bde16399e208daaa279dbf455802dd1edec58e7d 100644
--- a/conda/js/src/components/toolchain/ToolchainEditor.jsx
+++ b/conda/js/src/components/toolchain/ToolchainEditor.jsx
@@ -34,6 +34,7 @@ import { getValidToolchainObj as getValidObj } from '@helpers/beat';
 import type { BeatObject } from '@helpers/beat';
 import { fetchLayout, genModuleApiFuncs } from '@helpers/api';
 
+import * as Actions from '@store/actions.js';
 import * as Selectors from '@store/selectors.js';
 import type { FlattenedDatabaseEntry } from '@store/selectors';
 
@@ -66,6 +67,7 @@ type Props = {
 	analyzerAlgorithms: BeatObject[],
 	// func to save changes on the current tc
 	saveFunc: (BeatObject) => any,
+	updateFunc: (BeatObject) => any,
 };
 
 // represents a timeline of state changes
@@ -79,8 +81,6 @@ type History = {
 };
 
 type State = {
-	// unsaved changes
-	cache: any,
 	// info for the modal for editing blocks
 	// if the fields are undefined, the modal shouldnt be up
 	modalBlockInfo: {
@@ -101,11 +101,11 @@ type State = {
 };
 
 // generates a new history object whenever the user does an action that changes state
-const generateNewHistory = (state: State): History => {
+const generateNewHistory = (state: State, data: any): History => {
 	return {
 		past: [
 			...state.history.past,
-			state.cache,
+			jsonClone(data),
 		],
 		future: [],
 	};
@@ -120,7 +120,6 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 	}
 
 	state = {
-		cache: getValidObj(this.props.data),
 		modalBlockInfo: {
 			name: undefined,
 			set: undefined,
@@ -136,77 +135,92 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 	}
 
 	// if the toolchain was updated, reset specific state fields
-	componentWillReceiveProps = (nextProps: Props) => {
+	UNSAFE_componentWillReceiveProps = (nextProps: Props) => {
+		/*
 		this.setState({
-			cache: getValidObj(nextProps.data),
 			history: generateNewHistory(this.state),
 		});
+		*/
 	}
 
-	// helper to set the contents (this.state.cache.contents) object
+	// helper to set the contents (this.props.data.contents) object
 	setContents = (newContents: any) => {
 		this.setState((prevState, props) => ({
-			cache: {
-				...prevState.cache,
-				contents: {
-					...prevState.cache.contents,
-					...newContents,
-				}
-			},
-			history: generateNewHistory(prevState),
+			history: generateNewHistory(prevState, props.data),
 		}));
+
+		this.props.updateFunc({
+			...this.props.data,
+			contents: {
+				...this.props.data.contents,
+				...newContents,
+			}
+		});
 	}
 
-	// helper to set the groups (this.state.cache.extraContents.groups)
+	// helper to set the groups (this.props.data.extraContents.groups)
 	setGroups = (groups: Group[]) => {
 		this.setState((prevState, props) => ({
-			cache: {
-				...prevState.cache,
-				extraContents: {
-					...prevState.cache.extraContents,
-					groups,
-				}
-			},
-			history: generateNewHistory(prevState),
+			history: generateNewHistory(prevState, props.data),
 		}));
+
+		this.props.updateFunc({
+			...this.props.data,
+			extraContents: {
+				...this.props.data.extraContents,
+				groups,
+			}
+		});
 	}
 
 	// undoes history by saving the current state to the future
 	// and switching to the latest history state
 	undoHistory = () => {
-		this.setState((prevState) => {
-			if(prevState.history.past.length === 0)
-				return prevState;
-			const newPast = [...prevState.history.past];
-			const nextCache = newPast.pop();
-			const newFuture = [...prevState.history.future, prevState.cache];
-			return {
-				cache: nextCache,
-				history: {
-					past: newPast,
-					future: newFuture,
-				},
-			};
+		if(this.state.history.past.length === 0)
+			return this.state;
+
+		const newPast = [...this.state.history.past];
+		const newData = newPast.pop();
+
+		const newFuture = [...this.state.history.future, jsonClone(this.props.data)];
+		this.setState({
+			history: {
+				past: newPast,
+				future: newFuture,
+			},
 		});
+
+		if(!newData){
+			console.error(`No past state found!`);
+			return;
+		}
+
+		this.props.updateFunc(newData);
 	};
 
 	// redoes history by putting the current state in the past
 	// and switching to the earliest future state
 	redoHistory = () => {
-		this.setState((prevState) => {
-			if(prevState.history.future.length === 0)
-				return prevState;
-			const newFuture = [...prevState.history.future];
-			const nextCache = newFuture.pop();
-			const newPast = [...prevState.history.past, prevState.cache];
-			return {
-				cache: nextCache,
-				history: {
-					past: newPast,
-					future: newFuture,
-				},
-			};
+		if(this.state.history.future.length === 0)
+			return this.state;
+
+		const newFuture = [...this.state.history.future];
+		const newData = newFuture.pop();
+
+		const newPast = [...this.state.history.past, jsonClone(this.props.data)];
+		this.setState({
+			history: {
+				past: newPast,
+				future: newFuture,
+			},
 		});
+
+		if(!newData){
+			console.error(`No future state found!`);
+			return;
+		}
+
+		this.props.updateFunc(newData);
 	};
 
 	// toggles whether the object insert modal is active or not
@@ -221,15 +235,15 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 
 	// renames a group from an old name to a new one
 	renameGroup = (oldName: string, newName: string) => {
-		this.setGroups(this.state.cache.extraContents.groups.map(g => g.name === oldName ? {...g, name: newName} : g));
+		this.setGroups(this.props.data.extraContents.groups.map(g => g.name === oldName ? {...g, name: newName} : g));
 	}
 
 	// finds a block by name from the three block sub-arrays:
 	// blocks (normal blocks), datasets (dataset blocks), analyzers (analyzer blocks)
 	findBlock = (name: string): BlockType => {
-		const b = this.state.cache.contents.blocks.find(b => b.name === name) ||
-			this.state.cache.contents.datasets.find(b => b.name === name) ||
-			this.state.cache.contents.analyzers.find(b => b.name === name)
+		const b = this.props.data.contents.blocks.find(b => b.name === name) ||
+			this.props.data.contents.datasets.find(b => b.name === name) ||
+			this.props.data.contents.analyzers.find(b => b.name === name)
 		;
 		if(!b)
 			throw new Error(`invalid block name: ${ name }`);
@@ -240,7 +254,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 
 	// creates a connection between a block's output and a block's input with a specific channel
 	createConnections = (connectionData: ConnectionType[]) => {
-		const rep = this.state.cache.contents.representation;
+		const rep = this.props.data.contents.representation;
 
 		// assign empty synchronized_channel vals on blocks that are getting their first connection
 		const toBlockNamesAndChannels = connectionData.map(c => [c.to.split('.')[0], c.channel]);
@@ -259,8 +273,8 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 			;
 		};
 
-		const newBlocks = assignBlockChannels(this.state.cache.contents.blocks);
-		const newAnalyzers = assignBlockChannels(this.state.cache.contents.analyzers);
+		const newBlocks = assignBlockChannels(this.props.data.contents.blocks);
+		const newAnalyzers = assignBlockChannels(this.props.data.contents.analyzers);
 
 
 		const newRepConns = generateConnectionRepresentations(connectionData);
@@ -268,7 +282,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 			blocks: newBlocks,
 			analyzers: newAnalyzers,
 			connections: [
-				...this.state.cache.contents.connections,
+				...this.props.data.contents.connections,
 				...connectionData,
 			],
 			representation: {
@@ -283,7 +297,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 
 	// updates a blocks location in the graphical editor by providing an x & y offset relative to the current location.
 	updateBlockLocations = (bLocs: {blockName: string, x: number, y: number}[]) => {
-		const rep = this.state.cache.contents.representation;
+		const rep = this.props.data.contents.representation;
 		const newReps = bLocs
 		.map(bLoc => ({ [bLoc.blockName]: { ...rep.blocks[bLoc.blockName], col: bLoc.x, row: bLoc.y }}))
 		.reduce((o, bLoc) => ({ ...o, ...bLoc }), {});;
@@ -310,7 +324,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 		};
 
 		// update the block & conn representation with the new names
-		const rep = {...this.state.cache.contents.representation};
+		const rep = {...this.props.data.contents.representation};
 		rep.blocks = {...rep.blocks};
 		rep.blocks[newName] = rep.blocks[oldName];
 		delete rep.blocks[oldName];
@@ -333,10 +347,10 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 
 		// update blocks & connections
 		const newContents = {
-			...this.state.cache.contents,
-			[set]: this.state.cache.contents[set].map(s => s.name === oldName ? {...s, name: newName} : s),
+			...this.props.data.contents,
+			[set]: this.props.data.contents[set].map(s => s.name === oldName ? {...s, name: newName} : s),
 			// update the conns, both the names of the blocks and the channel
-			connections: this.state.cache.contents.connections.map(c => {
+			connections: this.props.data.contents.connections.map(c => {
 				if(!c.from.includes(oldName) && !c.to.includes(oldName) && c.channel !== oldName)
 					return c;
 
@@ -354,34 +368,34 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 
 		// if the changed block is a dataset, update the synchronized_channel on all blocks using its old name
 		if(set === 'datasets'){
-			newContents['blocks'] = this.state.cache.contents.blocks
+			newContents['blocks'] = this.props.data.contents.blocks
 			.map(s => s.synchronized_channel === oldName ? {...s, synchronized_channel: newName} : s)
 			;
 
-			newContents['analyzers'] = this.state.cache.contents.analyzers
+			newContents['analyzers'] = this.props.data.contents.analyzers
 			.map(s => s.synchronized_channel === oldName ? {...s, synchronized_channel: newName} : s)
 			;
 		}
 
-		const newGroups = this.state.cache.extraContents.groups
+		const newGroups = this.props.data.extraContents.groups
 		.map(({ name, blocks }) => ({ name, blocks: blocks.map(n => n === oldName ? newName : n) }));
-		console.log(newName);
-		this.setState((prevState) => ({
-			cache: {
-				...prevState.cache,
-				contents: newContents,
-				extraContents: {
-					...prevState.cache.extraContents,
-					groups: newGroups,
-				},
-			},
-			history: generateNewHistory(prevState),
+		this.setState((prevState, props) => ({
+			history: generateNewHistory(prevState, props.data),
 			modalBlockInfo: {
 				active: true,
 				name: newName,
 				set
 			}
 		}));
+
+		this.props.updateFunc({
+			...this.props.data,
+			contents: newContents,
+			extraContents: {
+				...this.props.data.extraContents,
+				groups: newGroups,
+			},
+		});
 	}
 
 	// updates a block's input or output name
@@ -396,7 +410,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 				toSplit[1] = to === combinedName ? newName : toSplit[1];
 			return [fromSplit.join('.'), toSplit.join('.')];
 		};
-		const rep = {...this.state.cache.contents.representation};
+		const rep = {...this.props.data.contents.representation};
 
 		rep.connections = Object.entries(rep.connections).map(([name, rep]) => {
 			if(!name.includes(`.${ oldName }`))
@@ -410,8 +424,8 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 		.reduce((cs, [name, map]) => ({...cs, [name]: rep}), {})
 		;
 		const newContents = {
-			...this.state.cache.contents,
-			[set]: this.state.cache.contents[set].map(s => {
+			...this.props.data.contents,
+			[set]: this.props.data.contents[set].map(s => {
 				if(s.name !== blockName)
 					return s;
 				const newBlock = {
@@ -423,7 +437,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 					newBlock.outputs = newBlock.outputs.map(str => str === oldName ? newName : str);
 				return newBlock;
 			}),
-			connections: this.state.cache.contents.connections.map(c => {
+			connections: this.props.data.contents.connections.map(c => {
 				if(!c.from.includes(`.${ oldName }`) && !c.to.includes(`.${ oldName }`))
 					return c;
 				const updated = updateConn(c.from, c.to);
@@ -449,7 +463,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 			newBlock = {};
 			if(set === 'blocks' || set === 'analyzers'){
 				newBlock.inputs = [];
-				newBlock.synchronized_channel = Object.keys(this.state.cache.contents.representation.channel_colors)[0];
+				newBlock.synchronized_channel = Object.keys(this.props.data.contents.representation.channel_colors)[0];
 			}
 			if(set === 'blocks' || set === 'datasets'){
 				newBlock.outputs = [];
@@ -489,13 +503,13 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 		const sets = blockData.map(b => b[1]);
 
 		const rep = {
-			...this.state.cache.contents.representation,
+			...this.props.data.contents.representation,
 			blocks: {
-				...this.state.cache.contents.representation.blocks,
+				...this.props.data.contents.representation.blocks,
 				...newBlocks.reduce((newReps, b) => ({...newReps, [b.block.name]: b.rep}), {}),
 			},
 			channel_colors: {
-				...this.state.cache.contents.representation.channel_colors,
+				...this.props.data.contents.representation.channel_colors,
 				...newBlocks.filter(b => b.channelColor !== null)
 				.reduce((newColors, b) => ({...newColors, [b.block.name]: b.channelColor}), {}),
 			}
@@ -503,18 +517,18 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 
 
 		const newContents = {
-			blocks: [...this.state.cache.contents.blocks, ...newBlocks.filter((b, i) => sets[i] === 'blocks').map(b => b.block)],
-			datasets: [...this.state.cache.contents.datasets, ...newBlocks.filter((b, i) => sets[i] === 'datasets').map(b => b.block)],
-			analyzers: [...this.state.cache.contents.analyzers, ...newBlocks.filter((b, i) => sets[i] === 'analyzers').map(b => b.block)],
+			blocks: [...this.props.data.contents.blocks, ...newBlocks.filter((b, i) => sets[i] === 'blocks').map(b => b.block)],
+			datasets: [...this.props.data.contents.datasets, ...newBlocks.filter((b, i) => sets[i] === 'datasets').map(b => b.block)],
+			analyzers: [...this.props.data.contents.analyzers, ...newBlocks.filter((b, i) => sets[i] === 'analyzers').map(b => b.block)],
 			representation: rep,
-			connections: this.state.cache.contents.connections,
+			connections: this.props.data.contents.connections,
 		};
 
 		// if the blocks werent copied from an external toolchain,
 		// check for connection info from the copied blocks and create new connections between the new blocks
 		if(!connections){
 			const copyBlocks = blockData.filter(bd => bd.length > 4);
-			const newConnections: ConnectionType[] = [...this.state.cache.contents.connections].map(({ from, to, channel }) => {
+			const newConnections: ConnectionType[] = [...this.props.data.contents.connections].map(({ from, to, channel }) => {
 				const fromBlock = copyBlocks.find(bd => from.startsWith(`${ bd[4].name }.`));
 				const toBlock = copyBlocks.find(bd => to.startsWith(`${ bd[4].name }.`));
 				if(!fromBlock || !toBlock)
@@ -531,13 +545,13 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 				}
 			})
 			.filter(c => c);
-			newContents.connections = [...this.state.cache.contents.connections, ...newConnections];
+			newContents.connections = [...this.props.data.contents.connections, ...newConnections];
 			const newRepConns = generateConnectionRepresentations(newConnections);
 			newContents.representation.connections = {...rep.connections, ...newRepConns};
 		} else {
 			// add the new connections from the copied toolchain
 			const newConnections = connections;
-			newContents.connections = [...this.state.cache.contents.connections, ...newConnections];
+			newContents.connections = [...this.props.data.contents.connections, ...newConnections];
 			const newRepConns = generateConnectionRepresentations(newConnections);
 			newContents.representation.connections = {...rep.connections, ...newRepConns};
 		}
@@ -548,7 +562,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 	// add a new input or output to a block
 	addBlockIO = (blockName: string, set: BlockSet, ioType: 'input' | 'output', newName: string) => {
 		const newContents = {
-			[set]: this.state.cache.contents[set].map(s => {
+			[set]: this.props.data.contents[set].map(s => {
 				if(s.name !== blockName)
 					return s;
 				const newBlock = {
@@ -569,7 +583,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 	// as well as any connections to/from it
 	// if it was the sole member of a group, deletes the group too
 	deleteBlocks = (names: string[]) => {
-		const rep = jsonClone(this.state.cache.contents.representation);
+		const rep = jsonClone(this.props.data.contents.representation);
 
 		names.forEach(name => {
 			delete rep.blocks[name];
@@ -588,11 +602,11 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 		//console.log(Object.keys(rep.connections));
 
 		const newContents = {
-			...this.state.cache.contents,
-			blocks: this.state.cache.contents.blocks.filter(s => !names.includes(s.name)),
-			datasets: this.state.cache.contents.datasets.filter(s => !names.includes(s.name)),
-			analyzers: this.state.cache.contents.analyzers.filter(s => !names.includes(s.name)),
-			connections: this.state.cache.contents.connections.filter(c => {
+			...this.props.data.contents,
+			blocks: this.props.data.contents.blocks.filter(s => !names.includes(s.name)),
+			datasets: this.props.data.contents.datasets.filter(s => !names.includes(s.name)),
+			analyzers: this.props.data.contents.analyzers.filter(s => !names.includes(s.name)),
+			connections: this.props.data.contents.connections.filter(c => {
 				if(names.find(blockName => c.to.startsWith(`${ blockName }.`) || c.from.startsWith(`${ blockName }.`)))
 					return false;
 				return true;
@@ -600,29 +614,28 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 			representation: rep,
 		};
 
-		const newGroups = this.state.cache.extraContents.groups
+		const newGroups = this.props.data.extraContents.groups
 		.map(({ name, blocks }) => ({ name, blocks: blocks.filter(n => !names.includes(n)) }))
 		.filter(g => g.blocks.length !== 0);
 
 		this.setState({
-			cache: {
-				...this.state.cache,
-				contents: newContents,
-				extraContents: {
-					...this.state.cache.extraContents,
-					groups: newGroups,
-				},
-			},
-			history: generateNewHistory(this.state),
+			history: generateNewHistory(this.state, this.props.data),
 		});
 
-		this.setContents(newContents);
+		this.props.updateFunc({
+			...this.props.data,
+			contents: newContents,
+			extraContents: {
+				...this.props.data.extraContents,
+				groups: newGroups,
+			},
+		});
 	}
 
 	// deletes a connection
 	// looks at the representation object and the connections array
 	deleteConnection = (cn: ConnectionType) => {
-		const rep = {...this.state.cache.contents.representation};
+		const rep = {...this.props.data.contents.representation};
 
 		rep.connections = Object.entries(rep.connections).filter(([name, rep]) => {
 			const [from, to] = name.split('/');
@@ -634,7 +647,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 		;
 
 		const newContents = {
-			connections: this.state.cache.contents.connections.filter(c => {
+			connections: this.props.data.contents.connections.filter(c => {
 				if(c.from === cn.from && c.to === cn.to)
 					return false;
 				return true;
@@ -648,7 +661,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 	// deletes an input or output from a block,
 	// as well as any connections connected to it
 	deleteBlockIO = (blockName: string, set: BlockSet, ioType: 'input' | 'output', ioName: string) => {
-		const rep = {...this.state.cache.contents.representation};
+		const rep = {...this.props.data.contents.representation};
 
 		const connectionLabel = `${ blockName }.${ ioName }`;
 
@@ -666,8 +679,8 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 		.reduce((cs, [name, rep]) => ({...cs, [name]: rep}), {})
 		;
 		const newContents = {
-			...this.state.cache.contents,
-			[set]: this.state.cache.contents[set].map(s => {
+			...this.props.data.contents,
+			[set]: this.props.data.contents[set].map(s => {
 				if(s.name !== blockName)
 					return s;
 				const newBlock = {
@@ -679,7 +692,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 					newBlock.outputs = newBlock.outputs.filter(str => str !== ioName);
 				return newBlock;
 			}),
-			connections: this.state.cache.contents.connections.filter(c => {
+			connections: this.props.data.contents.connections.filter(c => {
 				if(ioType === 'input' && c.to === connectionLabel)
 					return false;
 				if(ioType === 'output' && c.from === connectionLabel)
@@ -694,10 +707,10 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 	// changes the block's sync'd channel
 	// also updates all connections from the block
 	updateBlockChannel = (blockName: string, set: BlockSet, channel: string) => {
-		const queue = [this.state.cache.contents[set].find(b => b.name === blockName)];
+		const queue = [this.props.data.contents[set].find(b => b.name === blockName)];
 		const oldChannel = `${ queue[0].synchronized_channel }`;
-		const bNames = Object.keys(this.state.cache.contents.representation.blocks);
-		const conns = this.state.cache.contents.connections;
+		const bNames = Object.keys(this.props.data.contents.representation.blocks);
+		const conns = this.props.data.contents.connections;
 		const updatedBlocks: { [string]: BlockType } = {};
 		const updatedConnections: { [string]: ConnectionType } = {};
 		while(queue.length > 0){
@@ -732,11 +745,11 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 		}
 
 		const newContents = {
-			...this.state.cache.contents,
-			datasets: this.state.cache.contents.datasets.map(b => updatedBlocks[b.name] || b),
-			blocks: this.state.cache.contents.blocks.map(b => updatedBlocks[b.name] || b),
-			analyzers: this.state.cache.contents.analyzers.map(b => updatedBlocks[b.name] || b),
-			connections: this.state.cache.contents.connections.map(c => updatedConnections[connectionToId(c)] || c),
+			...this.props.data.contents,
+			datasets: this.props.data.contents.datasets.map(b => updatedBlocks[b.name] || b),
+			blocks: this.props.data.contents.blocks.map(b => updatedBlocks[b.name] || b),
+			analyzers: this.props.data.contents.analyzers.map(b => updatedBlocks[b.name] || b),
+			connections: this.props.data.contents.connections.map(c => updatedConnections[connectionToId(c)] || c),
 		};
 
 		this.setContents(newContents);
@@ -744,9 +757,9 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 
 	// gets possible channels the block can sync to
 	getPossibleChannels = (blockName: string) => {
-		const relConns = this.state.cache.contents.connections.filter(c => c.to.split('.')[0] === blockName) || [];
+		const relConns = this.props.data.contents.connections.filter(c => c.to.split('.')[0] === blockName) || [];
 		const possibleChannels = Array.from(new Set(relConns.map(c => c.channel)))
-		.reduce((o, channel) => ({...o, [channel]: this.state.cache.contents.representation.channel_colors[channel]}), {});
+		.reduce((o, channel) => ({...o, [channel]: this.props.data.contents.representation.channel_colors[channel]}), {});
 
 		return possibleChannels;
 	}
@@ -756,7 +769,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 	// handles the left click on the svg's background
 	// shows a menu to add/paste blocks at the click location
 	handleSvgContextMenu = (e: any, data: { x: number, y: number, selectBlocks: (string[]) => any, clicked: string }) => {
-		const {blocks, datasets, analyzers, representation} = this.state.cache.contents;
+		const {blocks, datasets, analyzers, representation} = this.props.data.contents;
 		const { x, y, selectBlocks, clicked } = data;
 		let newBlockName = '';
 		const usedNames = this.getUsedNames();
@@ -847,7 +860,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 	// handles a right click on a group
 	handleGroupContextMenu = (e: any, data: { group: string, selectBlocks: (BlockType[]) => any, clicked: string }) => {
 		const {group, clicked, selectBlocks} = data;
-		const groups = this.state.cache.extraContents.groups;
+		const groups = this.props.data.extraContents.groups;
 		const g = groups.find(g => g.name === group);
 		switch(clicked){
 			case 'delete':
@@ -873,14 +886,14 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 	// gets all the used names in the toolchain:
 	// group names & block names
 	getUsedNames = (): string[] => [
-		...this.state.cache.extraContents.groups.map(g => g.name),
-		...Object.keys(this.state.cache.contents.representation.blocks)
+		...this.props.data.extraContents.groups.map(g => g.name),
+		...Object.keys(this.props.data.contents.representation.blocks)
 	];
 
 	// handles a right click on an area selection
 	handleAreaSelectContextMenu = (e: any, data: { selection: BlockType[], clicked: string }) => {
 		const {selection, clicked} = data;
-		const groups = this.state.cache.extraContents.groups;
+		const groups = this.props.data.extraContents.groups;
 		switch(clicked){
 			case 'createGroup':
 				const newGroupName = generateNewKey('group', this.getUsedNames());
@@ -927,10 +940,9 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 	autoLayout = async () => {
 		// first save the tc to the BEAT prefix
 		const serverSaveFunc = genModuleApiFuncs('toolchain').put;
-		await serverSaveFunc(this.state.cache);
+		await serverSaveFunc(this.props.data);
 		// then fetch the new layout
-		const json = await fetchLayout(this.state.cache.name);
-		console.log(json);
+		const json = await fetchLayout(this.props.data.name);
 
 		// transform the received layout into objs for updateBlockLocations
 		const posRaw = json.objects
@@ -972,12 +984,12 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 				<Row>
 					<GraphicalEditor
 						interactable
-						repData={this.state.cache.contents.representation}
-						blocks={this.state.cache.contents.blocks}
-						datasets={this.state.cache.contents.datasets}
-						analyzers={this.state.cache.contents.analyzers}
-						connections={this.state.cache.contents.connections}
-						groups={this.state.cache.extraContents.groups}
+						repData={this.props.data.contents.representation}
+						blocks={this.props.data.contents.blocks}
+						datasets={this.props.data.contents.datasets}
+						analyzers={this.props.data.contents.analyzers}
+						connections={this.props.data.contents.connections}
+						groups={this.props.data.extraContents.groups}
 						handleBlockClick={this.handleBlockClick}
 						updateBlockLocations={this.updateBlockLocations}
 						createConnection={(from: string, to: string, channel: string) => this.createConnections([{ from, to, channel }])}
@@ -1149,7 +1161,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 		const possibleChannels = active ? this.getPossibleChannels(name) : {};
 		return (
 			<EditModal
-				data={this.state.cache.contents[set].find(d => d.name === name)}
+				data={this.props.data.contents[set].find(d => d.name === name)}
 				active={active}
 				toggle={() => {
 					this.setState({
@@ -1159,7 +1171,7 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 						}
 					});
 				}}
-				blockNames={Object.keys(this.state.cache.contents.representation.blocks) || []}
+				blockNames={Object.keys(this.props.data.contents.representation.blocks) || []}
 				updateBlockName={(newName: string) => {
 					this.updateBlockName(set, name, newName);
 				}}
@@ -1234,9 +1246,9 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 					className='mx-auto'
 					outline
 					color='secondary'
-					onClick={() => this.props.saveFunc(this.state.cache)}
+					onClick={() => this.props.saveFunc(this.props.data)}
 				>
-					Save Changes (Changes are <ValidSchemaBadge entity='toolchain' obj={this.state.cache} />)
+					Save Changes (Changes are <ValidSchemaBadge entity='toolchain' obj={this.props.data} />)
 				</Button>
 			</div>
 			<Form onSubmit={(e) => e.preventDefault()}>
@@ -1247,8 +1259,8 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 							type='text'
 							className='tcDescription'
 							placeholder='Toolchain description...'
-							value={this.state.cache.contents['description']}
-							onChange={e => this.setContents({ ...this.state.cache.contents, 'description': e.target.value})}
+							value={this.props.data.contents['description']}
+							onChange={e => this.setContents({ ...this.props.data.contents, 'description': e.target.value})}
 						/>
 					</FormGroup>
 				</FormGroup>
@@ -1262,14 +1274,24 @@ export class ToolchainEditor extends React.PureComponent<Props, State> {
 }
 
 const mapStateToProps = (state, ownProps) => {
+	const tcs = Selectors.toolchainGet(state);
 	const obj = {
-		toolchains: Selectors.toolchainGet(state),
+		toolchains: tcs,
 		databases: Selectors.databaseGet(state),
 		sets: Selectors.flattenedDatabases(state),
 		normalAlgorithms: Selectors.normalBlocks(state),
 		analyzerAlgorithms: Selectors.analyzerBlocks(state),
+		data: tcs[ownProps.index] || getValidObj()
 	};
 	return obj;
 };
 
-export default connect(mapStateToProps)(ToolchainEditor);
+const mapDispatchToProps = (dispatch, ownProps) => ({
+	// replace the obj in the Redux store with the new object
+	updateFunc: (obj) => {
+		console.log(`dispatching for ${ obj.name }`);
+		dispatch(Actions[`toolchainUpdate`](obj.name, obj));
+	},
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(ToolchainEditor);