Files
react-from-zero/16-advanced-integration.html

138 lines
3.9 KiB
HTML

<!doctype html>
<title>16 Advanced Integration - React From Zero</title>
<script src="https://unpkg.com/react@16.4.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.4.0/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/create-react-class@15.6.3/create-react-class.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://unpkg.com/d3@4.7.3/build/d3.min.js">
// Sometimes we need to integrate more complex
// libraries. Libraries that want to use the
// DOM directly or require asynchronous interaction.
// In this example we use D3.js, a free InfoVis library.
</script>
<div id="app"></div>
<script type="text/babel">
// Since D3 needs to interact directly with the DOM we
// should use a component class, because it can store
// references to its DOM-elements.
var Visual = createReactClass({
// We simply render an empty canvas and tell React to
// store its reference after the render
render: function() {
return <canvas ref={this.handleRef} width={500} height={500}/>
},
handleRef: function(canvas) {
this.canvas = canvas
},
// After the first render, we grab the reference
// to the canvas element in the DOM and pass it
// to the library
componentDidMount: function() {
// Here we also use some additional color configuration
drawGraph(this.canvas, this.props.color)
},
// We also have some fine-granular control over the re-render
// With the use of this lifecylce method
shouldComponentUpdate: function(nextProps, nextState) {
// Here we could tell our library the new data for props
// or state, so it can update the DOM elements on its own
// At the end we always return false so our render method
// isn't called and the canvas element isn't replaced
return false
},
// This lifecycle method can be used to free resources
// before the component will be removed from the DOM.
// Our canvas will be removed for sure, but often there
// is state for the library, other objects, listeners etc.
// they could be stored on the component and should be
// deleted to prevent memory leaks
componentWillUnmount() {},
})
// Now we can use the library as a component
// No need for global IDs, every instance has its own canvas
// reference stored, also its own color property
var reactElement =
<div>
<Visual color="#f00"/>
<Visual color="#0f0"/>
<Visual color="#00f"/>
</div>
ReactDOM.render(reactElement, document.getElementById("app"))
// Wrapping the library interaction into a function
function drawGraph(canvas, strokeColor) {
// An example from http://bl.ocks.org/mbostock/1b64ec067fcfc51e7471d944f51f1611
// its realeased under the GPL-V3
var n = 20
var nodes = d3.range(n * n).map(function(i) {
return {index: i}
})
var links = []
for (var y = 0; y < n; ++y) {
for (var x = 0; x < n; ++x) {
if (y > 0) links.push({source: (y - 1) * n + x, target: y * n + x});
if (x > 0) links.push({source: y * n + (x - 1), target: y * n + x});
}
}
d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody().strength(-30))
.force("link", d3.forceLink(links).distance(20).iterations(10))
.on("tick", ticked)
var context = canvas.getContext("2d")
var width = canvas.width
var height = canvas.height
function ticked() {
context.clearRect(0, 0, width, height)
context.save()
context.translate(width / 2, height / 2)
context.beginPath()
links.forEach(drawLink)
context.strokeStyle = "#aaa"
context.stroke()
context.beginPath()
nodes.forEach(drawNode)
context.fill()
context.strokeStyle = strokeColor
context.stroke()
context.restore()
}
function drawLink(d) {
context.moveTo(d.source.x, d.source.y)
context.lineTo(d.target.x, d.target.y)
}
function drawNode(d) {
context.moveTo(d.x + 3, d.y);
context.arc(d.x, d.y, 3, 0, 2 * Math.PI)
}
}
</script>