Update react component without re-rendering entire element

I want to prototype some charts from http://nivo.rocks. I have some success (after reading through the docs and Mike’s recent post on jsx) but can’t figure out how to provoke React to update the chart when the data changes rather than re-render the entire chart.

Here’s what I have now:

If you “roll the dice” with http://nivo.rocks/chord you’ll see nice transitions. But in my notebook, if you update the data manually, it appears that the entire svg element is getting re-rendered (which is expected, but not desired).

I’ve tried to prefix the data parameter with mutable to prevent re-rendering, but that doesn’t seem to work.

Hey, sure - here’s an example: https://beta.observablehq.com/d/8700eeab71f938c5

I’ve added some notes to the notebook about what the essential differences are: the main thing is that it uses a consistent div as the render target, instead of recreating a div on each render.

Thanks Tom – this is the example I was looking for. I had actually come to the same conclusion – that I was clobbering the save div but hadn’t had time to circle back and try it out. Many thanks!

@tom Is there a way (or what is the best way) to abstract the long string between the `` into a variable?

<Chord width={height} height={width} matrix={chord_data} keys={[...

I want to separate the long specs (of which I will have several) to be able to reuse the chart generation instructions.

I tried doing this (naively) by creating a cell called chart_specs = <Chord... and then calling
ReactDOM.render(jsx({ Chord, chord_data, chord_spec, height: 400, width })chart_specs, circle)
But that didn’t seem to work.


Also, the Responsive elements don’t seem to work e.g. if you change <Chord... to <ResponsiveChord... I’m guessing because they are expecting context?

I don’t know how to answer the rest of your question, but note that you need another set of parentheses when passing chart_specs to jsx. Try:

jsx({ Chord, chord_data, chord_spec, height: 400, width })(chart_specs)

(note that jsx(stuff) returns a function, so you need to pass it chart_specs as an argument).

@bgchen Thanks for the tip. I tried that approach but it didn’t work for me. In the end the following worked

linex = ReactDOM.render(jsx({ ResponsiveLine, line_data, line_specs, height: 400, width: 900 })'${line_specs}', line_dom)
Note: The single quotes around ${line_specs} are supposed to be template ` delimiters, but I can’t figure out how to escape them here.

I also resolved the ResonsiveLine issue – you need to make sure your target div has a height style property defined or it won’t render (see nivo docs).

I used line_dom = html'<div style="height: 400px; width: 100%;" />'

Which seems to work.

still broke on my end:

just comes up nivo blank:

Thanks @RandomFractals – I think something broke with importing ReactDOM = r('react-dom') since @tom looked at this earlier. Could it be an issue with how Observable imports?

I looked up react-dom with https://beta.observablehq.com/@tmcw/module-require-debugger and it came back with require('react-dom@16.4.2/index.js').catch(() => window.checkDCE) but I couldn’t get that to work.

@tom any ideas?

@RandomFractals The following seems to fix the issue:
ReactDOM = require('https://wzrd.in/standalone/react-dom@latest')

1 Like

now we talking :slight_smile:

cool chord diagram!

I’m glad you were able to get it to work! Note that two of the user links in your first paragraph are broken due to a missing “/” (also, note that my observable link is (confusingly) @bryangingechen, not that I really contributed enough to be acknowledged so kindly!).

As it turns out, my advice didn’t work because of a bug in my understanding of template literals. I had thought (incorrectly) that

someFunction(stuff)`some template string`

was equivalent to

spec = `some template string`; someFunction(stuff)(spec),

but in fact tag functions are a bit more complicated in general. As usual, reading the relevant web docs was enlightening. In short, your solution seems like the right one to me too.

By the way, to include backticks in markdown, just use multiple backticks as delimiters, here’s the discussion in the markdown syntax.

@bgchen Thanks for the follow-up. I had to update the reference to ReactDOM once again as it was failing again. Links are corrected. https://beta.observablehq.com/@john-clarke/nivo-react-components

Yeah, unfortunately, issues with unpkg (which require uses by default), wzrd.in, and bundle.run are all too frequent. There’s another thread about them here, with no solution, sadly.