React.JS
Enlightenment
Revisited
11-month story of me and ReactJS.
Artur Szott
@arturszott
11 months ago...
1 React
6 developers
. Frontend stack in the phase of research
Now
1 React
40 developers
8000+ commits within the frontend stack
React.js?
The V from the MVC.
The rest? M? C?
Checkbox.jsx
import React from 'react';
import { Input } from 'react-bootstrap';
class Checkbox extends React.Component {
render() {
return (
<Input
{...this.props}
type='checkbox'
labelClassName='formControl'
label={this.props.label}
/>
);
}
}
Checkbox.propTypes = {
label: React.PropTypes.string
};
export default Checkbox;
React views can consume some data
passed via props.
You can use any framework to render the react view.
import React from 'react';
import ReactDOM from 'react-dom';
import Checkbox from './Checkbox.jsx';
ReactDOM.render(<Checkbox label='meetJS' />, 'body');
Any
framework.
Brave people everywhere.
+
+
React reacts well with Flux...
Unidirectional application architecture.
...or one of the 15
flux implementations.
Math.floor((Math.random() * 15) + 1)
or check this helpful repo.
1. Facebook Flux
2. Fluxible by Yahoo
3. Reflux
4. Alt
5. Flummox
6. McFly
7. Lux
8. Material Flux
9. Redux
10. Redux + Flambeau
11. Nuclear.js
12. Fluxette
13. Fluxxor
14. Freezer
15. Your next great
flux implementation
Phases of
enlightenment
LEARNING CURVE IS A LIE.
DON’T TRUST PEOPLE OVER THE INTERNET.
1. Hatred.
But they said that React is awesome?
'awesome' !== 'easy';
People new to:
flux,
actions,
stores,
dispatchers,
props,
state,
lifecycle...
...will be lost.
./actions/updateImportantStatus.js
export default (context) => {
context.dispatch(UPDATE_IMPORTANT_STATUS, {
providerName: 'hc',
data: {
isAuthenticating: true
}
});
}
./components/LoginForm.jsx
import updateImportantStatus from '../actions/updateImportantStatus
class LoginForm extends BaseForm {
updateAuthenticationStatus() {
this.context.executeAction(updateImportantStatus);
}
render() {
return (
<form onSubmit={this.updateAuthenticationStatus.bind(this)}>
<Email ref='email' />
<Password ref='password'/>
<Checkbox ref='rememberMe' label=’Remember me’/>
<SubmitButton isBusy={this.props.isAuthenticating}> Login </SubmitButton>
</form>
);
}
}
Used to writing in
pure JS?
Say hello t0 JSX syntax
and ES6.
./components/pages/Login.jsx
class Login extends React.Component {
onValidationFailure(formErrors) {
const message = R.keys(formErrors).map((key) => {
return `${key}: ${formErrors[key]}`;
}).join(', ');
tracking.trackLoginFailure(this.context, { message });
}
render() {
return (
<div className='login-page-container'>
<FacebookScript appId={this.props.facebookAppId} />
<Page documentTitle='MeetJS Login' metaDescription='Hello MeetJS 2016!'>
<LoginForm ref='form'
isAuthenticating={this.props.isAuthenticating}
email={this.props.userEmail}
errorMessages={this.props.errorMessages}
onValidationFailure={this.onValidationFailure.bind(this)}
focusedElement={this.props.focusedElement}
/>
</Page>
</div>
);
}
}
2. Understanding.
I think I know what is happening there.
Knowing where to place my code
is definitely a big win.
- What to put inside the action?
- When to use props or state?
- Where to pour data into your app?
Old MVC habits can mislead you.
Treat the component like an instruction.
Components are the presentation of received data.
They can’t wait with executing callback after fired action.
3. Trust
I’m on the flow. My data is too.
One point of entry can be all you need.
Pass all necessary data at the top component and let the data
flow down the component tree, allowing child components
to align themselves.
Pass all “globals” at the top component.
PropTypes
are good for you.
Providing component
propTypes is one step
closer to build long
maintainable app.
./components/LoginForm.jsx
LoginForm.propTypes = {
isAuthenticating: React.PropTypes.bool,
email: React.PropTypes.string,
focusedElement: React.PropTypes.string,
errorMessages: React.PropTypes.shape({
password: React.PropTypes.string,
email: React.PropTypes.string
}),
onValidationSuccess: React.PropTypes.func,
onValidationFailure: React.PropTypes.func
};
You can always tell how component will
render based on the input
PropTypes are defining the input data of the component with
validation.
Warning: Failed propType: Required prop `appId` was
not specified in `FacebookScript`. Check the render method of `Login`.
Forgetting about propTypes definition is
not a problem with a little help
of eslint-react plugin.
5:50 error 'baseUrl' is missing in props validation react/prop-types
STACK EVOLUTION
IT’S A GOOD TIME TO START WRITING IN REACT,
BUT IT WASN’T ALWAYS THAT GOOD.
Before
So, you are using JSLint? Here comes JSX.
Now
You are using JSX? Here are the tools, pick some.
./test/unit/mocha.opts
--slow 5
--reporter dot
--recursive
--require ./test/unit/setup.js
--require ./test/throwOnWarnings.js
--compilers jsx:./test/babelCompiler.js
./package.json
"scripts": {
"test:unit": "NODE_ENV=test mocha test/unit --opts test/unit/mocha.opts"
}
command line:
npm run test:unit
Our working unit test
stack example.
./test/throwOnWarnings.js
const consoleError = console.error;
console.error = function (firstMessage, ...rest) {
if (firstMessage.startsWith('Warning:')) {
throw new Error(`Unexpected React Warning: ${firstMessage}`);
}
return consoleError(firstMessage, ...rest);
};
Never forget
about React warnings.
./test/throwOnWarnings.js
const hooks = require.extensions;
const extensions = Object.keys(hooks);
const limit = 15;
let count = 0;
extensions.forEach(function (extension) {
const originalHook = hooks[extension];
require.extensions[extension] = function (module, filename) {
if (filename.endsWith('node_modules/unwantedLibrary/index.js')) {
count += 1;
}
return originalHook(module, filename);
};
});
Made a mistake
in introducing
some lib?
./test/throwOnWarnings.js
process.on('exit', function () {
const diff = count - limit;
if (count > 0) {
console.log('Number of unwantedLibrary usages:', count);
}
if (diff > 0) {
throw new Error(
`The number of unwantedLibrary usages has been increased by ${diff}`
);
}
});
Restrict it usage!
Remove usages
and decrease
the limit over time.
CODE TESTABILITY
SOME CODE CAN BE TESTED WELL.
SOME CODE NOT, BUT IT’S NOT REACT’S FAULT.
Overriding dependencies is
a short win,
but in some time it will hit
you back.
Faster than you think.
Overriding deps. ./app/components/App.jsx
import isOnClient from '../lib/isOnClient';
./app/lib/isOnClient.js
export default function () {
return typeof document !== 'undefined';
}
./test/components/App.jsx
Application = proxyquire('../../../../app/components/Application', {
'../lib/isOnClient': () => true
});
Keeping the components small is the key.
Testing small component is a beautiful thing.
Isolating some parts of well determined behaviour allows you
to control the component only by changing input data and
testing the results.
Two ways of Reacting.
1. Stateless functions
Why? Simple.
./stateless/Header.jsx
import { detectSomething } from '../../lib/detectors';
const Header = (props) => {
const link = detectSomething(props.baseUrl) === 'meetJS'
? '/meetRegistration' : '/leave';
return (
<header>
<h1>Register</h1>
<a href={link} className='register-link'>Register now</a>
</header>
);
};
Two ways of Reacting.
2. Stateful components
Why? Extendable.
./stateful/Header.jsx
import { detectSomething } from '../../lib/detectors';
class Header extends React.Component {
render() {
const link = detectSomething(this.props.baseUrl) === 'meetJS'
? '/meetRegistration' : '/leave';
return (
<header>
<h1>Register</h1>
<a href={link} className='register-link'>Register now</a>
</header>
);
}
}
THE FUTURE OF
REACT
We have started knowing react when he was 0.13.0
Now he is 0.14.7 - what changed?
React is evolving.
He is kind enough not to break our code.
Every version introduces some changes, but they are well
described, showing developers that things will change.
This gave us some time, to remove more than 200 warnings
from our code, before version changed. Now we have 0.
React announced its stability.
In a strange way.
From the begining
people were expecting the final version 1.0.0
Surprise. We have now version 15.0.0.
SO… why we react?Artur Szott
@arturszott
Simplicity (after some trials and errors)
Testability (after learning finding good tools and setup)
Performance (haven’t encountered bottlenecks as fast as with backbone)
Bonus.
Inspire yourself by reading following articles:
Artur Szott
@arturszott
JSX looks like abomination, but it’s good for you.
https://medium.com/javascript-scene/jsx-looks-like-an-abomination-1c1ec351a918
9 things every React.js beginner should know
https://camjackson.net/post/9-things-every-reactjs-beginner-should-know
Using React is a Business Decision, Not a Technology Choice
https://blog.formidable.com/using-react-is-a-business-decision-not-a-technology-choice-
63c4641c5f7
The end.
You can work with me at HolidayCheck.
github.com/holidaycheck/jobs
Artur Szott
@arturszott
Photo: https://twitter.com/notbrent/status/696091475256352768 | Backgrounds: Unsplash.com

MeetJS Summit 2016: React.js enlightenment

  • 1.
    React.JS Enlightenment Revisited 11-month story ofme and ReactJS. Artur Szott @arturszott
  • 2.
    11 months ago... 1React 6 developers . Frontend stack in the phase of research
  • 3.
    Now 1 React 40 developers 8000+commits within the frontend stack
  • 4.
    React.js? The V fromthe MVC. The rest? M? C? Checkbox.jsx import React from 'react'; import { Input } from 'react-bootstrap'; class Checkbox extends React.Component { render() { return ( <Input {...this.props} type='checkbox' labelClassName='formControl' label={this.props.label} /> ); } } Checkbox.propTypes = { label: React.PropTypes.string }; export default Checkbox;
  • 5.
    React views canconsume some data passed via props. You can use any framework to render the react view. import React from 'react'; import ReactDOM from 'react-dom'; import Checkbox from './Checkbox.jsx'; ReactDOM.render(<Checkbox label='meetJS' />, 'body');
  • 6.
  • 7.
    React reacts wellwith Flux... Unidirectional application architecture.
  • 8.
    ...or one ofthe 15 flux implementations. Math.floor((Math.random() * 15) + 1) or check this helpful repo. 1. Facebook Flux 2. Fluxible by Yahoo 3. Reflux 4. Alt 5. Flummox 6. McFly 7. Lux 8. Material Flux 9. Redux 10. Redux + Flambeau 11. Nuclear.js 12. Fluxette 13. Fluxxor 14. Freezer 15. Your next great flux implementation
  • 9.
    Phases of enlightenment LEARNING CURVEIS A LIE. DON’T TRUST PEOPLE OVER THE INTERNET.
  • 10.
    1. Hatred. But theysaid that React is awesome? 'awesome' !== 'easy';
  • 11.
    People new to: flux, actions, stores, dispatchers, props, state, lifecycle... ...willbe lost. ./actions/updateImportantStatus.js export default (context) => { context.dispatch(UPDATE_IMPORTANT_STATUS, { providerName: 'hc', data: { isAuthenticating: true } }); } ./components/LoginForm.jsx import updateImportantStatus from '../actions/updateImportantStatus class LoginForm extends BaseForm { updateAuthenticationStatus() { this.context.executeAction(updateImportantStatus); } render() { return ( <form onSubmit={this.updateAuthenticationStatus.bind(this)}> <Email ref='email' /> <Password ref='password'/> <Checkbox ref='rememberMe' label=’Remember me’/> <SubmitButton isBusy={this.props.isAuthenticating}> Login </SubmitButton> </form> ); } }
  • 12.
    Used to writingin pure JS? Say hello t0 JSX syntax and ES6. ./components/pages/Login.jsx class Login extends React.Component { onValidationFailure(formErrors) { const message = R.keys(formErrors).map((key) => { return `${key}: ${formErrors[key]}`; }).join(', '); tracking.trackLoginFailure(this.context, { message }); } render() { return ( <div className='login-page-container'> <FacebookScript appId={this.props.facebookAppId} /> <Page documentTitle='MeetJS Login' metaDescription='Hello MeetJS 2016!'> <LoginForm ref='form' isAuthenticating={this.props.isAuthenticating} email={this.props.userEmail} errorMessages={this.props.errorMessages} onValidationFailure={this.onValidationFailure.bind(this)} focusedElement={this.props.focusedElement} /> </Page> </div> ); } }
  • 13.
    2. Understanding. I thinkI know what is happening there.
  • 14.
    Knowing where toplace my code is definitely a big win. - What to put inside the action? - When to use props or state? - Where to pour data into your app?
  • 15.
    Old MVC habitscan mislead you. Treat the component like an instruction. Components are the presentation of received data. They can’t wait with executing callback after fired action.
  • 16.
    3. Trust I’m onthe flow. My data is too.
  • 17.
    One point ofentry can be all you need. Pass all necessary data at the top component and let the data flow down the component tree, allowing child components to align themselves. Pass all “globals” at the top component.
  • 18.
    PropTypes are good foryou. Providing component propTypes is one step closer to build long maintainable app. ./components/LoginForm.jsx LoginForm.propTypes = { isAuthenticating: React.PropTypes.bool, email: React.PropTypes.string, focusedElement: React.PropTypes.string, errorMessages: React.PropTypes.shape({ password: React.PropTypes.string, email: React.PropTypes.string }), onValidationSuccess: React.PropTypes.func, onValidationFailure: React.PropTypes.func };
  • 19.
    You can alwaystell how component will render based on the input PropTypes are defining the input data of the component with validation. Warning: Failed propType: Required prop `appId` was not specified in `FacebookScript`. Check the render method of `Login`.
  • 20.
    Forgetting about propTypesdefinition is not a problem with a little help of eslint-react plugin. 5:50 error 'baseUrl' is missing in props validation react/prop-types
  • 21.
    STACK EVOLUTION IT’S AGOOD TIME TO START WRITING IN REACT, BUT IT WASN’T ALWAYS THAT GOOD.
  • 22.
    Before So, you areusing JSLint? Here comes JSX.
  • 23.
    Now You are usingJSX? Here are the tools, pick some.
  • 24.
    ./test/unit/mocha.opts --slow 5 --reporter dot --recursive --require./test/unit/setup.js --require ./test/throwOnWarnings.js --compilers jsx:./test/babelCompiler.js ./package.json "scripts": { "test:unit": "NODE_ENV=test mocha test/unit --opts test/unit/mocha.opts" } command line: npm run test:unit Our working unit test stack example.
  • 25.
    ./test/throwOnWarnings.js const consoleError =console.error; console.error = function (firstMessage, ...rest) { if (firstMessage.startsWith('Warning:')) { throw new Error(`Unexpected React Warning: ${firstMessage}`); } return consoleError(firstMessage, ...rest); }; Never forget about React warnings.
  • 26.
    ./test/throwOnWarnings.js const hooks =require.extensions; const extensions = Object.keys(hooks); const limit = 15; let count = 0; extensions.forEach(function (extension) { const originalHook = hooks[extension]; require.extensions[extension] = function (module, filename) { if (filename.endsWith('node_modules/unwantedLibrary/index.js')) { count += 1; } return originalHook(module, filename); }; }); Made a mistake in introducing some lib?
  • 27.
    ./test/throwOnWarnings.js process.on('exit', function (){ const diff = count - limit; if (count > 0) { console.log('Number of unwantedLibrary usages:', count); } if (diff > 0) { throw new Error( `The number of unwantedLibrary usages has been increased by ${diff}` ); } }); Restrict it usage! Remove usages and decrease the limit over time.
  • 28.
    CODE TESTABILITY SOME CODECAN BE TESTED WELL. SOME CODE NOT, BUT IT’S NOT REACT’S FAULT.
  • 29.
    Overriding dependencies is ashort win, but in some time it will hit you back. Faster than you think.
  • 30.
    Overriding deps. ./app/components/App.jsx importisOnClient from '../lib/isOnClient'; ./app/lib/isOnClient.js export default function () { return typeof document !== 'undefined'; } ./test/components/App.jsx Application = proxyquire('../../../../app/components/Application', { '../lib/isOnClient': () => true });
  • 31.
    Keeping the componentssmall is the key. Testing small component is a beautiful thing. Isolating some parts of well determined behaviour allows you to control the component only by changing input data and testing the results.
  • 32.
    Two ways ofReacting. 1. Stateless functions Why? Simple. ./stateless/Header.jsx import { detectSomething } from '../../lib/detectors'; const Header = (props) => { const link = detectSomething(props.baseUrl) === 'meetJS' ? '/meetRegistration' : '/leave'; return ( <header> <h1>Register</h1> <a href={link} className='register-link'>Register now</a> </header> ); };
  • 33.
    Two ways ofReacting. 2. Stateful components Why? Extendable. ./stateful/Header.jsx import { detectSomething } from '../../lib/detectors'; class Header extends React.Component { render() { const link = detectSomething(this.props.baseUrl) === 'meetJS' ? '/meetRegistration' : '/leave'; return ( <header> <h1>Register</h1> <a href={link} className='register-link'>Register now</a> </header> ); } }
  • 34.
    THE FUTURE OF REACT Wehave started knowing react when he was 0.13.0 Now he is 0.14.7 - what changed?
  • 35.
    React is evolving. Heis kind enough not to break our code. Every version introduces some changes, but they are well described, showing developers that things will change. This gave us some time, to remove more than 200 warnings from our code, before version changed. Now we have 0.
  • 36.
    React announced itsstability. In a strange way. From the begining people were expecting the final version 1.0.0
  • 37.
    Surprise. We havenow version 15.0.0.
  • 38.
    SO… why wereact?Artur Szott @arturszott Simplicity (after some trials and errors) Testability (after learning finding good tools and setup) Performance (haven’t encountered bottlenecks as fast as with backbone)
  • 39.
    Bonus. Inspire yourself byreading following articles: Artur Szott @arturszott JSX looks like abomination, but it’s good for you. https://medium.com/javascript-scene/jsx-looks-like-an-abomination-1c1ec351a918 9 things every React.js beginner should know https://camjackson.net/post/9-things-every-reactjs-beginner-should-know Using React is a Business Decision, Not a Technology Choice https://blog.formidable.com/using-react-is-a-business-decision-not-a-technology-choice- 63c4641c5f7
  • 40.
    The end. You canwork with me at HolidayCheck. github.com/holidaycheck/jobs Artur Szott @arturszott Photo: https://twitter.com/notbrent/status/696091475256352768 | Backgrounds: Unsplash.com