In short, you get some data, you join it with a selection of wholly or partially non-existent DOM, and then you work with the enter (new), update (existing) and exit (not required for the new data) selection. This is an extremely powerful metaphor for representing data and performing dynamic data updates using arbitrary mixes of SVG (or any other DOM) elements. (oh, based on this mechanism, you can build really beautiful visual transitions)
Here's a short introduction to the join idea in d3: https://bost.ocks.org/mike/join/
BTW, programming in d3.js already feels a whole lot like programming in a functional language.
D3 has some really nice graphing utilities, though. Their scale functions are handy and their geometry API is spectacular: https://github.com/mbostock/d3/wiki/Geometry
I've used d3 as a replacement for react and it performs quite well—though you have to be a bit more explicit when it comes to updates.