18
React + Redux + d3 Teemu Kurppa, ŌURA

React + Redux + d3.js

Embed Size (px)

Citation preview

Page 1: React + Redux + d3.js

React + Redux + d3Teemu Kurppa, ŌURA

Page 2: React + Redux + d3.js

[email protected]

www.ouraring.com

the world's first wellness ring

Head of Cloud

I work at

Page 3: React + Redux + d3.js

• Declarative UI Library

• Battle-tested by Facebook

• Component-based

• Inline HTML with JSX

Page 4: React + Redux + d3.js

• Predictable state management for JS Apps

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

Page 5: React + Redux + d3.js

d3.js

Page 6: React + Redux + 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

Page 7: React + Redux + d3.js

d3 - problems

• No components: code gets unwieldy very quickly

• State management mixed with UI code

Page 9: React + Redux + d3.js

d3 class pattern

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

Page 10: React + Redux + d3.js

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> ); } }

Page 11: React + Redux + d3.js

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> ); } }

Page 12: React + Redux + d3.js

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 }

Page 13: React + Redux + d3.js

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> ); } // … }

Page 14: React + Redux + d3.js

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> ) } }

Page 15: React + Redux + d3.js

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;

Page 16: React + Redux + d3.js

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> ); } }

Page 17: React + Redux + d3.js

Component CSS// SeriesBarChart.scss

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

Page 18: React + Redux + d3.js

Thanks! Questions?

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

Follow @teemu on Twitter to stay in touch.

Email: [email protected]