Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Entropy vs. React

Entropy vs. React

Decreasing entropy of your projects with React.
#reactjs #react

Andrei Daniliuk

June 18, 2015
Tweet

Other Decks in Programming

Transcript

  1. Entropy In thermodynamics, entropy is a measure of the number

    of specific ways in which a thermodynamic system may be arranged, commonly understood as a measure of disorder. * Entropy - Wikipedia, the free encyclopedia https://en.wikipedia.org/wiki/Entropy
  2. Questions How to organize/design your code? How to don't repeat

    yourself (DRY)? When, how and how often update DOM? How to update DOM fast? Where should application state and models settle? How to communicate between your components/modules? How to communicate with server? Where should communication logic settle? How the system will evolve over the time?
  3. Components based architecture <PersonasApp> <Header> <Title /> <Input /> </Header>

    <Personas> <Persona> <Name /> <Button /> </Persona> </Personas> <Footer> <Counter /> <TextInfo /> </Footer> </PersonasApp> Everything is component
  4. React Component * Thomas A. Anderson const Persona = React.createClass({

    render() { return ( <div className="persona-card"> <label>Thomas A. Anderson</label> </div> ); } }); React.render( React.createElement(Persona, {}), document.getElementById('persona') );
  5. const Persona = React.createClass({ displayName: 'Persona', render() { return (

    React.createElement( 'div', {className: 'persona-card'}, React.createElement( 'label', null, this.props.name ) ) ); } }); JSX JavaScript syntax extension Compiled JSX https://facebook.github.io/react/jsx-compiler.html const Persona = React.createClass({ render() { return ( <div className="persona-card"> <label>{this.props.name}</label> </div> ); } });
  6. Composing components const PersonasApp = React.createClass({ render() { return (

    <div> <Header /> <Personas personas={this.state.personas} /> <Footer personas={this.state.personas} /> </div> ); } });
  7. Component props <Persona name="Thomas A. Anderson" status="wanted" matrixAware={true} contacts={this.state.contacts} {...this.props}

    /> const Personas = React.createClass({ propTypes: { name: React.PropTypes.string.isRequired, status: React.PropTypes.string, matrixAware: React.PropTypes.bool, contacts: React.PropTypes.array }, getDefaultProps() { return { status: '', matrixAware: false, contacts: [] }; } };
  8. Components state const Persona = React.createClass({ getInitialState() { return {

    editing: false }; }, _handleDoubleClick() { this.setState({ editing: true }); }, render() { if (this.state.editing) { return ( <input type="text" name="persona" defaultValue={this.props.name} /> ); } return ( <label onDoubleClick={this._handleDoubleClick}>{this.props.name}</label> ); } };
  9. componentDidMount • Invoked once after the first render • Runs

    on client side only • DOM is accessible at this moment • Good point for 3d party libs integration componentDidMount() { PersonasStore.listen(this._onChange); PersonasActions.fetch(); }
  10. componentWillUnmount • Invoked immediately before a component is unmounted from

    the DOM • Perform any necessary cleanup in this method componentWillUnmount() { PersonasStore.unlisten(this._onChange); }
  11. _handleChange(event) { this.setState({ value: event.target.value }); }, _handleKeyDown(event) { if

    (event.keyCode === ENTER_KEY_CODE) { this._save(); } }, render() { return ( <input id={this.props.id} onBlur={this._save} onChange={this._handleChange} onKeyDown={this._handleKeyDown} value={this.state.value} /> ); } Events - SyntheticEvent
  12. • Good as lifecycle hooks, or when need to fill

    the state • But will complicate things if used just as helpers // PureRenderMixin.js export default { shouldComponentUpdate(nextProps, nextState) { return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState); } }; // PersonasApp.js const PersonasApp = React.createClass({ mixins: [PureRenderMixin], render() { /… } }); Mixins
  13. • render is not called if shouldComponentUpdate returns false (except

    for forceUpdate call) • PureRenderMixin implements shouldComponentUpdate • immutable-js provides immutable data structures const Component = React.createClass({ shouldComponentUpdate(nextProps, nextState) { return false; }, render() { // ... } }); Adv.Performance - Pure Components
  14. Will rerender on client string renderToString(ReactElement element) <footer data-reactid=".0.1"> <p

    data-reactid=".0.1.0"> 10 personas </p> <p data-reactid=".0.1.1"> Double-click to edit a persona </p> </footer> SEO Friendly - Isomorphic Render Will NOT rerender on client string renderToStaticMarkup(ReactElement element) <footer> <p> 10 personas </p> <p> Double-click to edit a persona </p> </footer>
  15. • Automatically finds tests to execute in your repo •

    Automatically mocks dependencies for you when running your tests • Allows you to test asynchronous code synchronously • Runs your tests with a fake DOM implementation (via jsdom) so that your tests can run on the command line • Runs tests in parallel processes so that they finish sooner - unfortunately we experienced issues with performance Jest
  16. Jest test describe('render - Component', () => { jest.dontMock('../components/component.es6'); const

    Component = require('../components/component.es6'); it('renders Component when details are provided', () => { const component = TestUtils.renderIntoDocument( <Component /> ); component.setState({ details: { data: 'data' } }, () => { const detailsElement = TestUtils.findRenderedDOMComponentWithClass(component, 'card card__details'); expect(detailsElement).toBeDefined(); }); }); });
  17. Mocha • Better performance • No automocking, means better control

    on mocking with sinon and proxyquire • Your beloved chai assertion library, with sinon-chai plugin • Also runs tests with a fake DOM implementation (via jsdom) so that your tests can run on the command line • And more...
  18. Mocha test describe('render - Component', () => { const Component

    = require('../components/component.es6'); it('renders Component when details are provided', () => { const component = TestUtils.renderIntoDocument( <Component /> ); component.setState({ details: { data: 'data' } }, () => { const componentNode = React.findDOMNode(component); expect(componentNode).to.exist; expect(componentNode.tagName).to.equal('DIV'); expect(componentNode.className).to.equal('card card__details'); }); }); });
  19. Test Utilities renderIntoDocument const component = TestUtils.renderIntoDocument(<Component />); scryRenderedDOMComponentsWithClass const

    cardComponents = TestUtils.scryRenderedDOMComponentsWithClass(component, 'card'); findRenderedDOMComponentWithClass const detailsComponent = TestUtils.findRenderedDOMComponentWithClass(component, 'card__details'); Simulate const node = React.findDOMNode(this.refs.input); React.addons.TestUtils.Simulate.click(node); React.addons.TestUtils.Simulate.change(node, {target: {value: 'Hello, world'}}); React.addons.TestUtils.Simulate.keyDown(node, {key: "Enter"});
  20. app/ css/ images/ js/ index.html dist/ node_modules/ tests/ .editorconfig .eslintrc

    .gitignore .scsslintrc gulpfile.js package.json README.md css/ module/ _all.scss _utility.scss _colors.scss ... partials/ _all.scss _buttons.scss _typography.scss ... vendor/ _all.scss _grid.scss ... main.scss js/ actions/ personasActions.js ... components/ persona/ persona.js persona.scss personas/ personas.js personas.scss ... helpers/ api.js ... stores/ personasStore.js ... vendor/ html5shiv.js … alt.js app.js tests/ actions/ personasActions personasActions.fetch.spec.js personasActions.clear.spec.js ... components/ persona/ persona.render.js persona.handleClick.js ... personas/ personas.render.js personas.getInitialState.js ... stores/ personasStore/ personasStore.handleFetch.spec.js personasStore.handleClear.spec.js ... ...
  21. From our experience • Straightforward and fast render - virtual

    dom and immutable data rocks! • Automatic rerender when data changes - less headaches • Components based architecture - very well maintainable and easy to test • SEO friendly - built-in server-side rendering support (isomorphic apps) • Straightforward one-way direction app data flow with Flux - must have for complex apps working with data • Easy to start with - developers start writing their components quite fast
  22. Again from our experience • React is relatively young -

    so you might need to reinvent and do from scratch many things, e.g your components and controls library • React is not full MVC framework - it’s V library first - so you have to think about controller and model, but that means it’s easy to integrate it as just View to your existing apps • Some learning curve might be required to do it in a right way - but it’s quite easy to start use it out of the box • Be careful with performance on mobile devices - it’s not really about React itself but about your surrounding code
  23. Block – Element – Modifier .my-element - there is a

    block .my-element__sub-element - there is a element (the 2 underscores denote sub elements) .my-element__sub-elelement—highlighted - there might be a modifier e.g. (the 2 hyphens denote a modifier state