# React Docs Notes --- ## Main Concepts --- ### JSX Represents Objects Babel compiles JSX down to `React.createElement()` calls (by [babel-plugin-transform-react-jsx](https://github.com/babel/babel/tree/7.0/packages/babel-plugin-transform-react-jsx)) and return an element tree. These two examples are identical: ```javascript const element = ( <h1 className="greeting"> Hello, world! </h1> ); ``` ```javascript const element = React.createElement( 'h1', // type {className: 'greeting'}, // [props] 'Hello, world!' // [...children] ); ``` --- which creates object like this: ```javascript // Note: this structure is simplified const element = { type: 'h1', // type: string | function | component props: { className: 'greeting', children: 'Hello, world!' } }; ``` > An element is a plain **object** describing a component instance or DOM node and its desired properties. --- ### Rendering :::info 1. `render` (depending on the return value of `shouldComponentUpdate`) 2. Virtual DOM Diff ([Immutable.js](https://immutable-js.github.io/immutable-js/) recommended) ::: - `false`, `null`, `undefined`, and `true` are valid children. They simply don’t render. ```javascript <div /> <div></div> <div>{false}</div> <div>{null}</div> <div>{undefined}</div> <div>{true}</div> ``` - Some of “falsy” values are still rendered. e.g. 0 would be rendered. ```javascript <React.Fragment> {props.messages.length && <div>There are messages.</div>} </React.Fragment> ``` --- ### Reconciliation > When you use React, at a single point in time you can think of the `render()` function as creating a **tree** of React elements. On the next state or props update, that `render()` function will return a different tree of React elements. React then needs to figure out how to efficiently update the UI to match the most recent tree. :::info 1. Two elements of different types will produce different trees. 2. The developer can hint at which child elements may be stable across different renders with a key prop. ::: #### The Diffing Algorithm - **Elements of different types**: unmounts elements and have their state destroyed. e.g. from `<a>` to `<img>`, or from `<Article>` to `<Comment>`, or from `<Button>` to `<div>` - **DOM element of the same type**: only updates the changed attributes - **Component elements of the same type**: updates props, which calls `componentWillReceiveProps()` and `componentWillUpdate()`, then `render()` - **Recursion**: `key` attribute (e.g. [key=index](https://reactjs.org/redirect-to-codepen/reconciliation/index-used-as-key), [key=id](https://reactjs.org/redirect-to-codepen/reconciliation/no-index-used-as-key)) - Unique - A key cannot be identical to that of a sibling component. - Static - A key should not ever change between renders. #### Render Props: a simple technique for sharing code between React components using a prop whose value is a function. - **Higher Order Component**: is a function that takes a component and returns a new component. --- ### State Updates May Be Asynchronous React may batch multiple `setState()` calls into a single update for performance. e.g. [not using function](https://codepen.io/stuku/pen/bQpmKo?editors=0010), [using function](https://codepen.io/stuku/pen/wQGYYr?editors=0010) --- ### Handling Events ```javascript // okay render() { return <MyInput onChange={e => this.props.update(e.target.value)} /> } // or update(e) { this.props.update(e.target.value); } render() { return <MyInput onChange={this.update.bind(this)} /> } ``` --- ```javascript // better constructor(props) { super(props); this.update = this.update.bind(this); } // or update = (e) => { this.props.update(e.target.value); } render() { return <MyInput onChange={this.update} /> } ``` [Try it on CodePen](https://codepen.io/stuku/pen/bQLOvO?editors=0010) --- ### Pure Component and Stateless Component #### When to Use Pure Components? - no nested data structure - stateless but lifecycle methods needed #### When to Use Stateless Components? very small UI view where re-render cost won’t matter that much (`React.memo` has been added as as an alternative in React 16) --- ### Integrating with Other Libraries within HOC ([e.g.](https://codepen.io/gaearon/pen/PmWwwa?editors=0010)) --- ## Changes in React 16 --- ### React Fiber: an reimplementation of React’s core algorithm - priority-based update system --- ### New Render Return Types: Fragments and Strings ```javascript render() { // No need to wrap list items in an extra element! return [ // Don't forget the keys :) <li key="A">First item</li>, <li key="B">Second item</li>, <li key="C">Third item</li>, ]; } // or render() { return "Look ma, no spans!"; } ``` [Try it on CodePen](https://codepen.io/stuku/pen/VVaoqg?editors=0010) --- ### Error Boundary catch errors **during rendering, in lifecycle methods, and in constructors of the whole tree below them**, and display a fallback UI -- which is an implication -- as of React 16, errors that were not caught by any error boundary will result in unmounting of the whole React component tree ([e.g](https://codepen.io/gaearon/pen/wqvxGa?editors=0010)). Note: Error boundaries do **not** catch errors for: - Event handlers - Asynchronous code (e.g. setTimeout) - Server side rendering - Errors thrown in the error boundary itself (rather than its children --- ```javascript class PotentialError extends React.Component { constructor(props) { super(props); this.state = { error: false }; } static getDerivedStateFromError(error) { // Update state so the next render will show the fallback UI. return { error: true }; } componentDidCatch(error, info) { this.setState({ error, info }); } render() { if (this.state.error) { return <h1>Error: {this.state.info && this.state.info.componentStack}</h1>; } return this.props.children; } } ``` --- ### Portals Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component. ```javascript 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 ); } ``` [Try it on CodePen](https://codepen.io/gaearon/pen/yzMaBd) --- ### Support for Custom DOM Attributes ```javascript // Your code: <div mycustomattribute="something" /> ``` ```javascript // React 15 output: <div /> ``` ```javascript // React 16 output: <div mycustomattribute="something" /> ``` [More attribute behaviors](https://github.com/facebook/react/blob/master/fixtures/attribute-behavior/AttributeTableSnapshot.md) --- ### Component Lifecycle Changes - `componentWillMount`, `componentWillReceiveProps`, and `componentWillUpdate` will be aliased with an “UNSAFE_” prefix - `getDerivedStateFromProps` and `getSnapshotBeforeUpdate` is being added [Check out this lifecycle diagram](http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/) --- ### Fragments group a list of children **without** adding extra nodes to the DOM. ```javascript function Glossary(props) { return ( <dl> {props.items.map(item => ( <Fragment key={item.id}> // or <></> <dt>{item.term}</dt> <dd>{item.description}</dd> </Fragment> ))} </dl> ); } ``` Note: `key` is the only attribute that can be passed to `Fragment` --- ### `React.memo` similar to PureComponent ```javascript function areEqual(prevProps, nextProps) { /* return true if passing nextProps to render would return the same result as passing prevProps to render, otherwise return false */ } const MyComponent = React.memo(props => ( /* only rerenders if props change */ ), areEqual); ``` Note: Unlike the `shouldComponentUpdate()` method on class components, the `areEqual` function returns `true` if the props are equal and `false` if the props are not equal. This is the **inverse** from shouldComponentUpdate. --- ### `React.lazy`: Code-Splitting with Suspense ```javascript import React, {lazy, Suspense} from 'react'; const OtherComponent = lazy(() => import('./OtherComponent')); function MyComponent() { return ( <Suspense maxDuration={1000} fallback={<div>Loading...</div>}> <OtherComponent /> </Suspense> ); } ``` --- ### New Context API ```javascript const ThemeContext = React.createContext('light'); class ThemeProvider extends React.Component { state = {theme: 'light'}; render() { return ( <ThemeContext.Provider value={this.state.theme}> {this.props.children} </ThemeContext.Provider> ); } } ``` --- ```javascript class ThemedButton extends React.Component { // only accessible in render method render() { return ( <ThemeContext.Consumer> {theme => <Button theme={theme} />} </ThemeContext.Consumer> ); } } ``` --- ```javascript // or class ThemedButton extends React.Component { static contextType = ThemeContext; componentDidMount() { let value = this.context; /* perform a side-effect at mount using the value of ThemeContext */ } /* componentWillReceiveProps(nextProps, nextContext) {} shouldComponentUpdate(nextProps, nextState, nextContext) {} componentWillUpdate(nextProps, nextState, nextContext) {} componentDidUpdate(nextProps, nextState, nextContext) {} */ render() { let value = this.context; /* render something based on the value of ThemeContext */ } } ``` --- ```javascript // or function ThemedButton(props, context) { return ( <Button theme={context.theme} /> ); } ThemedButton.contextTypes = { theme: React.PropTypes.string.isRequired } ``` Try it on CodePen: [React 15](https://codepen.io/stuku/pen/BGKgYO?editors=0010), [React 16](https://codepen.io/stuku/pen/ZmWNqm?editors=0010) --- ### Refs: `React.createRef`, `React.ForwardRef` ```javascript constructor(props) { super(props); // recent way this.textInput = null; this.myRef = el => { this.textInput = el; }; // in React 16 this.myRef = React.createRef(); } render() { return <div ref={this.myRef} />; } ``` --- ```javascript const FancyButton = React.forwardRef((props, ref) => ( <button ref={ref} className="FancyButton"> {props.children} </button> )); // You can now get a ref directly to the DOM button: const ref = React.createRef(); <FancyButton ref={ref}>Click me!</FancyButton>; ``` [Try it on CodePen](https://codepen.io/stuku/pen/bQwqZG?editors=0011) --- ### Dev Tool: [React Profiler](https://reactjs.org/blog/2018/09/10/introducing-the-react-profiler.html) --- ref: - [React Docs](https://reactjs.org/docs/hello-world.html) - [State updates might be asynchronous](https://stackoverflow.com/questions/45248204/state-updates-might-be-asynchronous) - [Lin Clark - A Cartoon Intro to Fiber - React Conf 2017](https://youtu.be/ZCuYPiUIONs) - [React Fiber Architecture](https://github.com/acdlite/react-fiber-architecture) - [Update on Async Rendering](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html)