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

Post on 15-Jul-2015

249 Views

Category:

Technology

9 Downloads

Preview:

Click to see full reader

TRANSCRIPT

ReactAlexey Volkov

Rumble Inc

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

in practice

alexey@rumble.me

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

Everything is a componentEverything is a component

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

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

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

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

Advantages

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

Disadvantages

Not a silver bulletNot a frameworkScatteringJSXYoungSomething else?

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

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

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.

Backbone ModelsBackbone Models

CSSCSS

Mobile WebMobile Web

D3D3

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

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

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

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

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

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

});

<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' } ] ...});

npm installnpm installreact-validator-mixinreact-validator-mixin

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

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

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

One global namespaceDependenciesSharing constants

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

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

'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>;

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 }

});

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

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

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

npm install react-stylernpm install react-styler

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

React + Mobile WebReact + Mobile Web

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

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

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

React + D3React + D3

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

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)

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 */}

CommonCommonD3 - calculationsD3 - renderingReact - stupidwrapper

WiseWiseD3 - calculationsReact - rendering

??

top related