D3.js is one of the leading JavaScript libraries for visualising data. It's powerful and flexible but can be hard to learn.

One point of confusion is D3's approach to data binding (i.e. keeping an array of data in sync with HTML or SVG elements).

Before version 5 the functions .enter() and .exit() were used to bind data.

However version 5 introduces a new function .join():

var myData = [ 10, 40, 30, 50, 20 ];

d3.select('.container')
.selectAll('circle')
.data(myData)
.join('circle')
.attr('r', function(d) { return d; });

The above snippet ensures each of myData's elements is bound to a circle element. Circles are added, removed and resized as necessary.

In version 4 the equivalent code was:

var myData = [ 10, 40, 30, 50, 20 ];

var u = d3.select('.container')
.selectAll('circle')
.data(myData);

u.enter()
.append('circle')
.merge(u)
.attr('r', function(d) { return d; });

u.exit()
.remove();

(The statement beginning u.enter() handles entering and updating circles and the final statement handles exiting circles.)

And in version 3:

var u = d3.select('.container')
.selectAll('circle')
.data(myData);

u.enter()
.append('circle');

u.attr('r', function(d) { return d; });

u.exit()
.remove();

(The statement beginning u.enter() handles entering circles, the next statement updates circles and the final one handles exiting circles.)

General update pattern

The general update pattern encapsulates the data binding code in a function (usually called update).

With D3 version 5 update() looks like:

function update() {
d3.select('.container')
.selectAll('circle')
.data(myData)
.join('circle')
.attr('r', function(d) {
return d;
})
// ...any other style or attribute updates
}

Whenever myData changes call update() to ensure the HTML/SVG elements stay in sync.

Here's a CodePen example showing the general update pattern being used to update a row of circles:

See the Pen D3 v5 enter/exit/update by Peter Cook (@createwithdata) on CodePen.

You can compare this with the equivalent examples for version 3 and version 4.

Summary

The addition of .join() is a big improvement to D3's data binding. It makes the code simpler and much easier to learn.

It even allows for fine-grained control over how elements enter and leave the page (which is what .enter() and .exit() were good at). This'll be the subject of another article.

I highly recommend getting to know .join() and hopefully it'll make things easier if you've ever struggled with .enter() and .exit()!