I've got a user that has some data on the page in this form:
[{ name: 'Jack', id: 1 }, { name: 'Ellen', id: 2 }, {name: 'Nick', id: 3}]
An Apollo query loads this data. The user can add names to or delete names from the page using a form. An Apollo mutation handles the add or delete requests. RefetchQueries gets called after the mutation, the state gets updated and the list of names gets rerendered.
The problem is that if I add a name, refetchQueries will return all 4 objects and, in return, all 4 objects get set to state.
[{ name: 'Jack', id: 1 }, { name: 'Ellen', id: 2 }, {name: 'Nick', id: 3}, { name: 'Mary', id: 4 }]
I would like to find out how to get the difference between the new and the old data. Then add or delete the right object from the state array, and not entirely reset the state. The id's used will always be unique.
loadData = (names, that) => {
that.setState({ loading:true });
let data = {};
data.names= [];
const oldNames = that.state.names;
names.map(name=> (
data.names.push({ name: name.name, id: name.id })
));
that.setState({names: data.names, loading: false });
}
Above function gets called in componentWillUpdate like this:
componentWillUpdate(nextProps, nextState) {
loadData(nextProps.names, this);
}
I am trying to change this function as follow:
updateData = (names, that) => {
let data = {};
data.names = [];
const oldNames = that.state.names ;
names.map(name => (
data.names.push({ name: name.name, id: name.id })
));
let difference = _(data.names)
.differenceBy(oldNames, 'id', 'name')
.map(_.partial(_.pick, _, 'id', 'name'))
.value();
if (data.names.length > oldNames.length)
that.setState(prevState => ({
names: [...prevState.names, {name: difference[0].name, id: difference[0].id}]
}))
}
But to find the difference between the old and new data in this way doesn't feel very good. I've tried solutions from Compare 2 arrays which returns difference, but I couldn't get it to work. I hope you can help me introduce a better way to do find the difference. In the example above I used lodash, but that's not a requirement. I also wonder if there is a better way. For example, directly get the result from the Apollo mutation and add this result to the State.
UPDATE mapping of nodes:
render() {
if (this.state.loading) { return <div>Loading...</div> }
const links = this.state.links.map( (link,i) => {
return (
<Link
linkClass={this.props.linkClass}
key={link.target+i}
data={link}
/>);
});
const nodes = this.state.nodes.map( (node) => {
return (
<Node
nodeClass={this.props.nodeClass}
data={node}
label={node.label}
key={node.id}
onClick={this.onClickHandler.bind(this, node)}
/>);
});
return (
<div className="graphContainer">
<svg className="graph" width={FORCE.width} height={FORCE.height}>
<g >
{links}
</g>
<g >
{nodes}
</g>
</svg>
</div>
);
}
}