jslab. Алексей Волков. "react на практике"

42
React Alexey Volkov Rumble Inc http://slides.com/alexeyvolkov/react-in-practice in practice [email protected]

Upload: geekslab

Post on 15-Jul-2015

248 views

Category:

Technology


9 download

TRANSCRIPT

Page 1: JSLab. Алексей Волков. "React на практике"

ReactAlexey Volkov

Rumble Inc

http://slides.com/alexeyvolkov/react-in-practice

in practice

[email protected]

Page 2: JSLab. Алексей Волков. "React на практике"
Page 3: JSLab. Алексей Волков. "React на практике"

FacebookSince May 2013Current version 0.13.1Popular and it's growinghttps://github.com/facebook/react/wiki/Sites-Using-React

Page 4: JSLab. Алексей Волков. "React на практике"

Everything is a componentEverything is a component

Page 5: JSLab. Алексей Волков. "React на практике"

var HelloMessage = React.createClass({ render: function() { return <div>Hello {this.props.name}</div>; }});

React.render(<HelloMessage name="John" />, mountNode);

Page 6: JSLab. Алексей Волков. "React на практике"

var Timer = React.createClass({ getInitialState: function() { return {secondsElapsed: 0}; }, tick: function() { this.setState({secondsElapsed: this.state.secondsElapsed + 1}); }, componentDidMount: function() { this.interval = setInterval(this.tick, 1000); }, componentWillUnmount: function() { clearInterval(this.interval); }, render: function() { return ( <div>Seconds Elapsed: {this.state.secondsElapsed}</div> ); }});

React.render(<Timer />, mountNode);

Page 7: JSLab. Алексей Волков. "React на практике"

Just the UI ("V" in MVC)Virtual DOMSynthetic eventsIsomorphicOne-way data flowNOT A FRAMEWORK

Page 8: JSLab. Алексей Волков. "React на практике"

Advantages

DeclarativePerformanceIsomorphicNice learning curveNice approach for separationof concernsNot a frameworkReact way = JavaScript waySomething else?

Page 9: JSLab. Алексей Волков. "React на практике"

Disadvantages

Not a silver bulletNot a frameworkScatteringJSXYoungSomething else?

Page 10: JSLab. Алексей Волков. "React на практике"

JSX hurts? Let's split it out

var Timer = React.createClass({ getInitialState: function() { return {secondsElapsed: 0}; }, tick: function() { this.setState({secondsElapsed: this.state.secondsElapsed + 1}); }, componentDidMount: function() { this.interval = setInterval(this.tick, 1000); }, componentWillUnmount: function() { clearInterval(this.interval); }, render: require('./Timer.render.js')});

React.render(React.createElement(Timer), mountNode);

Page 11: JSLab. Алексей Волков. "React на практике"
Page 12: JSLab. Алексей Волков. "React на практике"

Oyster

BBC

BigRen

tz

Beyondpad

BoomTown

Brigad

e

C5mail

CloudFlareCMNcom

Custom

Ink

Distiller

EMEX

EyeEm

FacebookFactlink

FaithStreet

Flexport

FiftyThreeMix

FINN FlightYogurt

Flipkart

GetStack

Guidebook

HackerOne

Html2CoffeeReact

ICX

Imgur

Instagram

Instru

cture

Iodine

Itele

KISSmetrics

Kupibi

let Layer

LeFigaro LockedOn

AddThis

mPATH

Musixmatch

Netflix

NoRed

Ink

Orobix

RevUP PaddleGuruPatience

PivotalTracker

Pixate

AirBnBPodio

Posiq

Quizlet

QuizUp

Recurly

Reddit Redfin

Rollbar

Rushmore

Sauspiel

SberBank

AsanaSe

llerC

rowd

Sonian

Stampsy

Storehouse

Swipely

Tilt

Timerepublik

TMdic

t

TvTag

Uniregistry

Venmo

Verbling

Versal

Wagon

Wired

YahooZendesk

Zvooq

Taobao

Alipay

Aha

ENCODE Encyclopedia of DNA Ele

Glip Mobile

Khan Academy

Madrone Software Analytcs

Maxwell Health

Minerva Project

Palo Alto Software

Planning Center Online

Prism Skylabs

Rally Software

Rockefeller Center

Sift Science

Talk by Teambition

Traitify Developer Portal

Trunk

Club

University of Cincinnati

Vida Digital

https://github.com/facebook/react/wiki/Sites-Using-React

Page 13: JSLab. Алексей Волков. "React на практике"

http://red-badger.com/blog/2015/03/04/react-native-the-killer-feature-that-nobody-talks-about/

"When I first looked at React I thought it wasinsane like most people. It takes such adifferent approach to web development thatit gives many people an immediate repulsivereaction. But of course the more I used it themore I realised I could never go back tobuilding web applications (or any front-endapp for that matter) any other way. Thepatterns react provides are an extremelypowerful way of building applications.

Page 14: JSLab. Алексей Волков. "React на практике"

Backbone ModelsBackbone Models

CSSCSS

Mobile WebMobile Web

D3D3

Page 15: JSLab. Алексей Волков. "React на практике"

Backbone Models? Why?Backbone Models? Why?SimpleWell-documentedLarge communityA long list of modules/plugins

Page 16: JSLab. Алексей Волков. "React на практике"

React + BackboneReact + Backbonehttps://github.com/magalhas/backbone-react-componenthttps://github.com/clayallsopp/react.backbone

Page 17: JSLab. Алексей Волков. "React на практике"

mixins: [mixinForm({ viewModelName: 'PushCampaign' })],...return <div> <c.Header title='< Push Campaign Editor' level={2} innerRight={buttons} /> <c.Fieldset caption='Message Composer'>

<c.FieldRow caption='Campaign Name:' className={this.form().labelClassName('Name')} hint={this.form().errors('Name')}> <c.Input type='text' {...this.form().attribute('Name')} /> </c.FieldRow>

<c.FieldRow caption='Description:' subCaption='For internal use only'> <c.Input type='textarea' {...this.form().attribute('Notes')} /> </c.FieldRow>

</c.Fieldset> <c.Fieldset caption='Message Targeting'>

<c.FieldRow caption='Send Notification To:' className={this.form().labelClassName('_targeting')} hint={this.form().errors('_targeting')}> <c.RadioList items={targetingItems} {...this.form().attribute('_targeting')} /> </c.FieldRow>

</c.Fieldset> <c.Header level={2} innerRight={buttons} /></div>;

Page 18: JSLab. Алексей Волков. "React на практике"

return <div> <c.Header title='< Push Campaign Editor' level={2} innerRight={buttons} /> <c.Fieldset caption='Message Composer'>

<c.FieldRow caption='Campaign Name:' className={this.form().labelClassName('Name')} hint={this.form().errors('Name')}> <c.Input type='text' value={this.form().value('Name')} className={this.form().inputClassName('Name')} onChange={this.form().handleChange('Name')} /> </c.FieldRow>

<c.FieldRow caption='Description:' subCaption='For internal use only'> <c.Input type='textarea' {...this.form().attribute('Notes')} /> </c.FieldRow>

</c.Fieldset> <c.Fieldset caption='Message Targeting'>

<c.FieldRow caption='Send Notification To:' className={this.form().labelClassName('_targeting')} hint={this.form().errors('_targeting')}> <c.RadioList items={targetingItems} {...this.form().attribute('_targeting')} /> </c.FieldRow>

</c.Fieldset> <c.Header level={2} innerRight={buttons} /></div>;

Page 19: JSLab. Алексей Волков. "React на практике"

componentWillMount: function () {

var model = this.form().model;

if (model.get('RegistrationId')) { model.set('_targeting', 'id'); }

// hide error message for RegistrationId (if user switched targeting type to "All") model.on('change:_targeting', function (model) { if (model.get('_targeting') === 'all') { model.set('RegistrationId', ''); this.form().validate({RegistrationId: model.get('RegistrationId')}); } }, this);

// clear link validation status on link editing model.on('change:ArticleUrl', function (model) { model.set('_articleUrlValid', null); if (_.isEmpty(model.get('ArticleUrl'))) { this.setState({notificationLink: LINK_EMPTY}); } else { this.forceUpdate(); } }, this); },

componentWillUnmount: function () { this.form().model.off(null, null, this); },

Page 20: JSLab. Алексей Волков. "React на практике"

var PushCampaign = Backbone.Model.extend({

defaults: { 'Name': '', 'Message': '', '_targeting': 'all' },

validation: { Name: { required: true }, Message: { required: true, maxLength: 250 },

RegistrationId: function (value) { if (this.get('_targeting') === 'id' && _.isEmpty(value)) { return 'Registration ID is missed'; } } }

});

Page 21: JSLab. Алексей Волков. "React на практике"

<FillPicker {...this.form().attribute('brandColors[name=main]')} />

<ImageUploader value={this.form().value('icons[name=ipad152x152].uri')} onChange={this.form().onChange('icons[name=ipad152x152].uri')} hint="152x152" deletable={true}/>

module.exports = Backbone.AssociatedModel.extend({ ... relations: [ { key: 'icons', type: Backbone.Many, relatedModel: 'Image', collectionType: 'ImagesCollection' }, { key: 'brandColors', type: Backbone.Many, relatedModel: Backbone.AssociatedModel.getRelatedModel('Fill'), collectionType: 'FillsCollection' } ] ...});

Page 22: JSLab. Алексей Волков. "React на практике"

npm installnpm installreact-validator-mixinreact-validator-mixin

https://github.com/RumbleInc/https://github.com/RumbleInc/react-validator-mixinreact-validator-mixin

Page 23: JSLab. Алексей Волков. "React на практике"

React + BackboneReact + BackboneForm data validationModels in flux storesRouter<Your ideas>?

Page 24: JSLab. Алексей Волков. "React на практике"

CSS. What is the problem?CSS. What is the problem?

One global namespaceDependenciesSharing constants

https://speakerdeck.com/vjeux/react-css-in-js

Page 25: JSLab. Алексей Волков. "React на практике"

CSS. Solutions?CSS. Solutions?"It's not a bug. It's a feature!"LESS/SASS/...BEM (block-element-modificator)

inline styles-anything: else?React-Styler

https://github.com/albburtsev/bem-cn

Page 26: JSLab. Алексей Волков. "React на практике"

'use strict';

var React = require('react/lib/ReactWithAddons'), styler = require('react-styler');

var Fieldset = React.createClass({

mixins: [styler.mixinFor('Fieldset')],

render: function () { var cn = this.className; /* jshint ignore:start */ return

/* jshint ignore:end */ }});

module.exports = Fieldset;

<fieldset className={cn()} style={this.props.style}> {this.props.caption && <legend className={cn('caption')}>{this.props.caption}</legend>} {this.props.children} </fieldset>;

Page 27: JSLab. Алексей Волков. "React на практике"

React.render(<Fieldset />, mountNode);

<fieldset class="Fieldset"> <legend class="Fieldset-caption">Caption</legend> ...</fieldset>

React.render(<Fieldset className="group1" />, mountNode);

<fieldset class="Fieldset Fieldset-group1"> <legend class="Fieldset-caption">Caption</legend> ...</fieldset>

styler.registerComponentStyles('Fieldset', { border: '1px solid #dbdbdb', padding: '35px 20px 20px',

'& + &': { marginTop: 25 },

'&-caption': { color: '#474747', padding: '0 8px', marginLeft: -8 }

});

Page 28: JSLab. Алексей Волков. "React на практике"

styler.registerComponentStyles('ChartPushNotifications', { '& .LineChart-lines path:nth-of-type(2)': { transform: 'translateY(-2px)' }, '& .LineChart-background': { fill: '#f5f5f5' }, '&-tooltip': { padding: 10, textAlign: 'center' }, '&-tooltip-channel': { fontSize: 12, maxWidth: 180 }, '&-tooltip-channel:before': { content: '"\\2588"', display: 'inline-block', width: 10, height: 10, overflow: 'hidden', verticalAlign: 'middle', marginRight: 5, fontSize: '1em', lineHeight: '10px' }});

Page 29: JSLab. Алексей Волков. "React на практике"

.ChartPushNotifications {}.ChartPushNotifications .LineChart-lines path:nth-of-type(2) { transform: translateY(-2px);}.ChartPushNotifications .LineChart-background { fill: #f5f5f5;}.ChartPushNotifications-tooltip { padding: 10px; text-align: center;}.ChartPushNotifications-tooltip-channel { font-size: 12px; max-width: 180px;}.ChartPushNotifications-tooltip-channel:before { content: "\2588"; display: inline-block; width: 10px; height: 10px; overflow: hidden; vertical-align: middle; margin-right: 5px; font-size: 1em; line-height: 10px;}

Page 30: JSLab. Алексей Волков. "React на практике"

Styler. Advantages?Styler. Advantages?BEM-like syntaxDependenciesNamespacesConstants/variablesVery easy to learn and use

Page 31: JSLab. Алексей Волков. "React на практике"

npm install react-stylernpm install react-styler

https://github.com/RumbleInc/https://github.com/RumbleInc/react-stylerreact-styler

Page 32: JSLab. Алексей Волков. "React на практике"

React + Mobile WebReact + Mobile Web

Page 33: JSLab. Алексей Волков. "React на практике"

React + Mobile WebReact + Mobile WebMinimize DOM modifications(use React, avoid jQuery)Optimise Virtual DOM(use shouldComponentUpdate)Be smart with CSS

Page 34: JSLab. Алексей Волков. "React на практике"

http://goo.gl/8Ybdgnhttp://goo.gl/8Ybdgn

Page 35: JSLab. Алексей Волков. "React на практике"

React + Mobile WebReact + Mobile Webreact-canvas (from Flipboard)react-native (congrats! just went public)Not WEB, it's native!

Page 36: JSLab. Алексей Волков. "React на практике"

React + D3React + D3

Page 37: JSLab. Алексей Волков. "React на практике"

React + D3. ApproachesReact + D3. Approaches1. React as a wrapper2. React as a renderer

Page 38: JSLab. Алексей Волков. "React на практике"

render: function() { return <div> <div ref="chart"></div> </div>;},

componentDidMount: function() { var chartDOMNode = this.refs['chart'].getDOMNode();

var m = 7; // number of samples per layer

var margin = {top: 4, right: 0, bottom: 10, left: 0}, that = this;

this.width = chartDOMNode.clientWidth - margin.left - margin.right; this.height = chartDOMNode.clientHeight - margin.top - margin.bottom;

var x = d3.scale.ordinal() .domain(d3.range(m)) .rangeRoundBands([39, this.width], 0.85, 0);

this.y = d3.scale.linear() .domain([0, 0]) .range([this.height, 0]);

this.yAxis = d3.svg.axis() .scale(this.y) .orient('left') .tickSize(-this.width, 0)

Page 39: JSLab. Алексей Волков. "React на практике"

render: function () { var cn = this.className;

/* jshint ignore:start */ var paths = prepareData(this.state.series);

return <div onClick={this.handleClickUpdate}> <svg width={width} height={height}> <g> {_.map(paths, function (paths, index) { return <g key={index}> {paths.series && <path {...paths.series} />} <g style={paths.series.style}> {_.map(paths.points, function (point, pointIndex) { return <path key={pointIndex} {...point} />; })} </g> </g>; }, this)} </g> </svg> </div>; /* jshint ignore:end */}

Page 40: JSLab. Алексей Волков. "React на практике"
Page 41: JSLab. Алексей Волков. "React на практике"

CommonCommonD3 - calculationsD3 - renderingReact - stupidwrapper

WiseWiseD3 - calculationsReact - rendering

Page 42: JSLab. Алексей Волков. "React на практике"

??