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

React 16 - In theory, in practice & in the future

React 16 - In theory, in practice & in the future

Giamir Buoncristiani

March 20, 2018
Tweet

More Decks by Giamir Buoncristiani

Other Decks in Programming

Transcript

  1. About me I am Giamir Buoncristiani. I am an Italian

    software engineer working at ThoughtWorks. I care passionately about UI development.
  2. What does it take to display a React application? Network

    Parse Compile Heap init Render Display I/O CPU
  3. How can we make the UX better? I/O CPU WHAT

    ABOUT DOING THE SAME AT THE FRAMEWORK LEVEL? CAN WE SPLIT REACT WORK INTO CHUNKS?
  4. React under the hood b div p span a i

    DATA Virtual DOM (JS) - $ React elements Real DOM - $$$ HTML elements
  5. React under the hood b div p span a i

    DATA Virtual DOM (JS) - $ React elements Real DOM - $$$ HTML elements b div p span a i
  6. React under the hood b div p span a i

    DATA Virtual DOM (JS) - $ React elements Real DOM - $$$ HTML elements b div p span a i b div p a i PROPS CHANGED span RECONCILER (REACT) NEW DATA span
  7. React under the hood b div p span a i

    DATA Virtual DOM (JS) - $ React elements Real DOM - $$$ HTML elements b div p a i b div p a i PROPS CHANGED span RECONCILER (REACT) NEW DATA span RENDERER (REACT-DOM) span
  8. The old reconciliation algorithm REACT STACK Recursion and the JS

    stack Browser main thread POTENTIAL LONG FRAME We cannot. How can we pause this process and resume later from where we left off? Can we split this work into chunks?
  9. The new reconciliation algorithm Gives control back to the main

    thread REACT FIBER Cooperative scheduling and requestIdleCallback Browser main thread React Fiber is a reimplementation of the React reconciler. It allows high priority updates to jump ahead low priority updates. It is built with full backward compatibility in mind Its new algorithm is a great foundation for async rendering features. It can pause visiting the tree at any time and restart later from where it left off.
  10. Reduced file size ~35% size decrease react (prod) react-dom (prod)

    react + react-dom (prod) 15.6.2 22.4KB (7.8KB) 127KB (38.9KB) 149.4KB (46.7KB) 16.2.0 6.5KB (2.8KB) 92.3KB (30.1KB) 98.8KB (32.9KB)
  11. New render return types Fragments Strings render() { return (

    <> Some text <h1>A heading</h1> More text </> ); } render() { return ‘Look ma, no spans!’; }
  12. Portals render() { // React does *not* create a new

    div. It renders the children into `domNode`. // `domNode` is any valid DOM node, regardless of its location in the DOM. return ReactDOM.createPortal( this.props.children, domNode, ); } Portals are a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component. Please prefer using portals over using multiple react roots.
  13. Error Boundaries class ErrorBoundary extends React.Component { constructor(props) { super(props);

    this.state = { hasError: false }; } render() { if (this.state.hasError) { return <h1>Something went wrong.</h1>; } return this.props.children; } } <MyApp> <ErrorBoundary> <WidgetA /> </ErrorBoundary> <ErrorBoundary> <WidgetB /> </ErrorBoundary> </MyApp> componentDidCatch(error, info) { this.setState({ hasError: true }); logErrorToMyService(error, info); }
  14. Improved server side rendering // Returns an HTML String ReactDOMServer.renderToString

    The server renderer has been completely rewritten // Returns a Readable stream that outputs an HTML string ReactDOMServer.renderToNodeStream
  15. JS environment requirements React 16 depends on the collection types

    Map & set // reactPolyfills.js import 'core-js/modules/es6.map'; import 'core-js/modules/es6.set'; // head.jsp <script type="text/javascript"> if(!("Map" in window && "Set" in window)) { document.write('<script src="/static/reactPolyfills.js?v=${version}"><\/script>'); } </script>
  16. Updating React 15 deprecated API React API breaking changes are

    minimal React codemod to update code which used the old api - import React, { PropTypes, Component } from 'react'; + import React, { Component } from 'react'; + import PropTypes from 'prop-types'; $ jscodeshift -t react-codemod/transforms/React-PropTypes-to-prop-types.js <path>
  17. Updating 3rd party libraries Package managers (npm, yarn, etc…) give

    you a warning for 3rd party libraries which have React 15 as a peer dependency. In our case these libraries worked fine after the upgrade to React 16. Anyhow we updated them to fix the package manager warnings. npm WARN [email protected] requires a peer of react@^15 but none is installed.
  18. Updating tests Upgrade to Enzyme 3 is necessary // Configure

    Enzyme 3+ const Enzyme = require('enzyme'); const Adapter = require('enzyme-adapter-react-16'); Enzyme.configure({ adapter: new Adapter() }); In our case fixing unit tests was the area which took the most effort.
  19. The new context API (16.3) A new version of context

    that provides a mechanism for a child component (Consumer) to access a value in an ancestor component (Provider). const MyContext = React.createContext( [defaultValue], [calculateChangedBits] ); const MyContextProvider = MyContext.Provider; const MyContextConsumer = MyContext.Consumer; <MyContextProvider value=“myContext”> // nestedComponents <MyContextConsumer> {value => ( <ComponentThatNeedsAccessToMyContext context={value} /> )} </MyContextConsumer> // nestedComponents </MyContextProvider>
  20. Time Slicing (under construction) class TimeSlicing extends Component { state

    = { data: [], text: “” }; handleChange = ({ target }) => { } render() { return( <> <input value={text} onChange={this.handleChange} /> <Graph data={data} /> </> ); } } this.setState({ text: target.value }); this.deferSetState({ data: target.value.length });
  21. Time Slicing (under construction) A generic way to ensure that

    high-priority updates like user input don’t get blocked by rendering low-priority updates. “Dan Abramov - React core team member”
  22. Suspense (under construction) class Wrapper extends Component { state =

    { data: null }; componentDidMount() { getData().then(data => { this.setState({ data }); }); } render() { return data ? <ComponentThatNeedsAsyncData data={data} /> : null } }
  23. Suspense (under construction) import { createFetcher } from ‘future’; const

    dataFetcher = createFetcher(getData); function Wrapper() { const data = dataFetcher.read(‘data’); return ( <ComponentThatNeedsAsyncData data={data} /> ); }
  24. Suspense (under construction) “Dan Abramov - React core team member”

    A generic way for components to suspend rendering while they load asynchronous data.
  25. Takeaways React 16 already uses the new Fiber reconciliation algorithm

    but it still does not take fully advantage of it just yet. At the moment Fiber is used on compatibility mode with the old React stack reconciler and all updates are treated synchronously. Upgrading to React 16 seems to be pretty painless and it brings some performance benefits especially if you are doing SSR. A new stable version of the context API will be available in React 16.3. Time Slicing and Suspense are the two main async rendering features the React core team is working on. Hopefully they will be ready by the end of the year, but you can start playing with them today cloning my demos from Github.