react + redux + d3.js

Post on 18-Mar-2018

1.203 Views

Category:

Software

3 Downloads

Preview:

Click to see full reader

TRANSCRIPT

React + Redux + d3Teemu Kurppa, ŌURA

teemu@ouraring.com

www.ouraring.com

the world's first wellness ring

Head of Cloud

I work at

• Declarative UI Library

• Battle-tested by Facebook

• Component-based

• Inline HTML with JSX

• Predictable state management for JS Apps

• Great tooling: logging, hot loading, time travel,…

d3.js

d3 - a lot of good stuff

• Handling data: Scales, Interpolators, Time Intervals, Time & Number formats

• Drawing: Paths, Areas, Shapes, Curves, Axes

• Data Structures for Visualization: Voronoi, Stack, Quadtrees, Polygons

• Drawing maps: Projections, Spherical Math, Geopaths

• Animations and Behaviour: Transitions, Easing, Zooming, Dragging, Forces

d3 - problems

• No components: code gets unwieldy very quickly

• State management mixed with UI code

d3 class pattern

class D3SeriesBarChart { constructor(el, props, state) { // setup code } update(el, props, state) { // data-dependent code } }

React wrapper for d3class SeriesBarChart extends Component { componentDidMount() { this.chart = new D3SeriesBarChart(this.svg, this.props, this.state); }

componentDidUpdate() { this.chart.update(this.svg, this.props, this.state); }

render() { return ( <svg ref={svg => this.svg = svg} width={this.props.width} height={this.props.height}> </svg> ); } }

React wrapper for d3class SeriesBarChart extends Component { componentDidMount() { this.chart = new D3SeriesBarChart(this.svg, this.props, this.state); }

componentDidUpdate() { this.chart.update(this.svg, this.props, this.state); }

render() { return ( <svg ref={svg => this.svg = svg} width={this.props.width} height={this.props.height}> </svg> ); } }

React wrapper for d3var T = React.PropTypes;

SeriesBarChart.propTypes = { width: T.number.isRequired, height: T.number.isRequired, data: T.shape({ x: T.arrayOf(T.number), y: T.arrayOf(T.arrayOf(T.number)), }).isRequired, mode: T.string.isRequired }

Demo Componentclass Demo extends Component { render() { return ( <div className={classNames(styles.demo)}> <form> {this.makeRadio('grouped', this.props.onSelectGrouped)} {this.makeRadio('stacked', this.props.onSelectStacked)} </form> <SeriesBarChart width={960} height={500}

data={this.props.data} mode={this.props.mode}/>

<div> <button onClick={this.props.onGenerateData}> Generate Data </button> </div> </div> ); } // … }

Demo Component

class Demo extends Component { // … makeRadio(mode, onChange) { return ( <label><input type=“radio" name=“mode" value={mode} onChange={onChange} checked={this.props.mode === mode}/> {mode} </label> ) } }

Redu Reducer// reducers.js

const initialState = { data: createData(), mode: 'grouped' };

function demo(state = initialState, action) { switch (action.type) { case CHANGE_MODE: return { ...state, mode: action.mode }; case GENERATE_DATA: return { ...state, data: createData() }; default: return state; } }

const rootReducer = combineReducers({ demo, });

export default rootReducer;

Component CSS// SeriesBarChart.jsx

import classNames from 'classnames'; const styles = require('./SeriesBarChart.scss');

class SeriesBarChart extends Component { render() {

return ( <svg className={classNames(styles.seriesbarchart)} ref={svg => this.svg = svg} width={this.props.width} height={this.props.height}> </svg> ); } }

Component CSS// SeriesBarChart.scss

.seriesbarchart { :global { .axis text { fill: blue; } } }

Thanks! Questions?

We are hiring: Python backend developers web front-end developers

Follow @teemu on Twitter to stay in touch.

Email: teemu@ouraring.com

top related