Skip to content

Instantly share code, notes, and snippets.

@djsmith42
Last active August 29, 2015 14:20
Show Gist options
  • Save djsmith42/135ed33c9b598ea33e04 to your computer and use it in GitHub Desktop.
Save djsmith42/135ed33c9b598ea33e04 to your computer and use it in GitHub Desktop.
This is a sprinkler system with zones and waterings.
A zone is an area that can be watered. It has an ID.
A watering is a scheduled event that consists of an ordered list of zones and how long to water them (durations). Duplicate zones are allowed.
So the API returns data like this:
```
GET /watering/123456
{
id: 123456,
start_time: "05:00",
durations: [{
zone_id: 2,
minutes: 10
},{
zone_id: 3,
minutes: 20
},{
zone_id: 2, # note this is the same zone_id as above
minutes: 10
}]
}
```
// To build a form to edit a watering in React, I can do this:
class WateringForm extends React.Component {
constructor(props) {
this.state = {
watering: props.watering
}
}
remove(index) {
this.state.waterings.durations.splice(index, 1);
this.setState({
waterings: this.state.waterings
})
}
render() {
return (
<ul>
{this.state.watering.durations.map((thing, index) => (
<li key={index}>
Zone: <input type="text" defaultValue={duration.zone_id} />
Time: <input type="text" defaultValue={duration.minutes} /> minutes
<button onClick={this.remove.bind(this, index)}>Remove</button>
</li>
))}
</ul>
)
}
}
The above code has a problem. When the user clicks "Remove", the last item from the list is removed in the DOM.
To fix it, I use this for the key:
<li key={index + "-" + duration.zone_id + "-" + duration.minutes}>
That way, you can have duplicates in the durations list, and the correct object is removed when the user clicks "remove".
Given this API, I don't know any other way around it.
@gaearon
Copy link

gaearon commented May 7, 2015

Can't you put a unique id into each duration when parsing API response? This way you'll be able to use it as key.

// API.js
let nextId = 0;
function getNextId() {
  return nextId++;
}

let response = JSON.parse(...);
response.durations.forEach(d => d.id = getNextId());

@djsmith42
Copy link
Author

That might work, but one wrinkle is that the the client polls the /waterings endpoint for updates every few seconds, so I would be generating new IDs every time it polls (I suppose I could skip assigning an ID for durations that already have one).

Question: With a key like: key={index + "-" + duration.zone_id + "-" + duration.minutes}, does React actually have to reconcile the vdom every time state changes?

@ryankshaw
Copy link

you could just do something like this https://jsfiddle.net/124ov9uz/ to completly abstract the idea of making unique ids out of your component and your backend data

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment