Intro


    <!-- Load React as script from CDN-->
    <!-- NOTE: when deploying, replace "development.js" with "production.min.js" -->
    <script
      src="https://unpkg.com/react@18/umd/react.development.js"
      crossorigin
    ></script>
    <script
      src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
      crossorigin
    ></script>
    <!-- Load React component -->
    <script src="like_button.js"></script>
  

    // import
    import * as ReactDOM from 'react-dom/client';
    // if you use ES5 with npm, you can write:
    var ReactDOM = require('react-dom/client');
  

JSX


    <MyButton color="blue" shadowSize={2}>
      Click Me
    </MyButton>
    // compiles into:
    React.createElement(
      MyButton,
      {color: 'blue', shadowSize: 2},
      'Click Me'
    )

    class Hello extends React.Component {
      render() {
        return <div>Hello {this.props.toWhat}</div>;
      }
    }
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(<Hello toWhat="World" />);
    // can be compiled to this code that does not use JSX:
    class Hello extends React.Component {
      render() {
        return React.createElement('div', null, `Hello ${this.props.toWhat}`);
      }
    }
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(React.createElement(Hello, {toWhat: 'World'}, null));

    // --- self-closing form of the tag if there are no children
    <div className="sidebar" />
    // compiles into:
    React.createElement(
      'div',
      {className: 'sidebar'},
      null
    )

    // --- React library must also always be in scope from JSX code
    // NOT required if using via script tag
    import React from 'react';
    import CustomButton from './CustomButton';
    function WarningButton() {
      // return React.createElement(CustomButton, {color: 'red'}, null);
      // --- if you use the JSX <Foo /> expression, Foo must be in scope
      return <CustomButton color="red" />;
    }

    // --- using dot notation for jsx type
    const MyComponents = {
      DatePicker: function DatePicker(props) {
        return <div>Imagine a {props.color} datepicker here.</div>;
      }
    }
    function BlueDatePicker() {
      return <MyComponents.DatePicker color="blue" />;
    }

    // --- user-defined components must be capitalized
    // to not mess with standard tags
    function Hello(props) {
      return <div>Hello {props.toWhat}</div>;
    }
    function HelloWorld() {
      return <Hello toWhat="World" />;
    }

    // --- if you do want to use a general expression to indicate the type of the element,
    // just assign it to a capitalized variable first
    import React from 'react';
    import { PhotoStory, VideoStory } from './stories';
    const components = {
      photo: PhotoStory,
      video: VideoStory
    };
    function Story(props) {
      // Wrong! JSX type can't be an expression.
      // return <components[props.storyType] story={props.story} />;
      // Correct! JSX type can be a capitalized variable.
      const SpecificStory = components[props.storyType];
      return <SpecificStory story={props.story} />;
    }
  

Props


    // --- pass any JS expression as a prop, by surrounding it with {}
    <MyComponent foo={1 + 2 + 3 + 4} /> // props.foo will be 10

    // --- put if/for in the surrounding code
    // check "conditional" and "list/key" section
    function NumberDescriber(props) {
      let description;
      if (props.number % 2 == 0) {
        description = <strong>even</strong>;
      } else {
        description = <i>odd</i>;
      }
      return <div>{props.number} is an {description} number</div>;
    }

    // --- string literals, following are equivalent
    <MyComponent message="hello world" />
    <MyComponent message={'hello world'} />
    <MyComponent message="<3" />
    <MyComponent message={'<3'} />

    // --- props default to "true", following are equivalent
    <MyTextBox autocomplete />
    <MyTextBox autocomplete={true} />

    // --- Spread Attributes
    // use "..." as a spread operator to pass the whole props object, following are equivalent
    function App1() {
      return <Greeting firstName="Ben" lastName="Hector" />;
    }
    function App2() {
      const props = {firstName: 'Ben', lastName: 'Hector'};
      return <Greeting {...props} />;
    }
    // pick specific props that component will consume
    // while passing all other props using the spread operator
    const Button = props => {
      const { kind, ...other } = props;
      const className = kind === "primary" ? "PrimaryButton" : "SecondaryButton";
      return <button className={className} {...other} />;
    };
    const App = () => {
      return (
        <div>
          <Button kind="primary" onClick={() => console.log("clicked!")}>
            Hello World!
          </Button>
        </div>
      );
    };
  

Children


    // JSX expressions that contain both an opening tag and a closing tag,
    // the content between those tags is passed as a special prop: props.children

    // --- string literals
    <MyComponent>Hello world!</MyComponent>
    // props.children in MyComponent will simply be the string "Hello world!"
    // HTML is unescaped, multiple spaces/tab/newline are removed

    // --- more JSX elements as the children
    <MyContainer>
      <MyFirstComponent />
      <MySecondComponent />
    </MyContainer>
    // mix together different types of children
    <div>
      Here is a list:
      <ul>
        <li>Item 1</li>
        <li>Item 2</li>
      </ul>
    </div>
    // return an array of elements
    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>,
      ];
    }

    // --- JS expressions as children
    // following are equivalent
    <MyComponent>foo</MyComponent>
    <MyComponent>{'foo'}</MyComponent>
    // render an HTML list
    function Item(props) {
      return <li>{props.message}</li>;
    }
    function TodoList() {
      const todos = ['finish doc', 'submit pr', 'nag dan to review'];
      return (
        <ul>
          {todos.map((message) => <Item key={message} message={message} />)}
        </ul>
      );
    }
    // mixed with other types of children
    function Hello(props) {
      return <div>Hello {props.addressee}!</div>;
    }

    // --- functions as children
    // take a callback as props.children
    // call the children callback numTimes to produce a repeated component
    function Repeat(props) {
      let items = [];
      for (let i = 0; i < props.numTimes; i++) {
        items.push(props.children(i));
      }
      return <div>{items}</div>;
    }
    function ListOfTenThings() {
      return (
        <Repeat numTimes={10}>
          {(index) => <div key={index}>This is item {index} in the list</div>}
        </Repeat>
      );
    }

    // --- booleans, null, and undefined are ignored
    // same thing:
    <div />
    <div></div>
    <div>{false}</div>
    <div>{null}</div>
    <div>{undefined}</div>
    <div>{true}</div>
    // can be useful to conditionally render React elements
    <div>
      {showHeader && <Header />}
      <Content />
    </div>
    // "falsy" values, such as the 0 number, are still rendered by React
    // make sure that the expression before && is always boolean
    <div>
      {props.messages.length > 0 &&
        <MessageList messages={props.messages} />
      }
    </div>
    // convert to a string if you want
    //a value like false, true, null, or undefined to appear in the output
    <div>
      My JavaScript variable is {String(myVariable)}.
    </div>
  

Example


    <!-- put React component inside DIV -->
    <!-- ONCE -->
    <div id="like_button_container"></div>
    <!-- MULTIPLE -->
    <div class="like_button_container" data-commentid="1"></div>
    <div class="like_button_container" data-commentid="2"></div>
  

    <script type="text/babel">
      'use strict';
      const e = React.createElement;
      class LikeButton extends React.Component {
        constructor(props) {
          super(props);
          this.state = { liked: false };
        }
        render() {
          if (this.state.liked) {
            return 'You liked comment number ' + this.props.commentID;
          }
          // return e(
          //   'button',
          //   { onClick: () => this.setState({ liked: true }) },
          //   'Like'
          //     + ( this.props.commentID ? ' number '+ this.props.commentID : '' )
          // );
          // // --- JSX version
          return (
            <button onClick={() => this.setState({ liked: true })}>
              Like
            </button>
          );
        }
      }
      // Find all DOM containers, and render Like buttons into them
      document.querySelectorAll('.like_button_container') // or #like_button_container
        .forEach(domContainer => {
          // Read the comment ID from a data-* attribute.
          const commentID = parseInt(domContainer.dataset.commentid, 10);
          const root = ReactDOM.createRoot(domContainer);
          root.render(e(LikeButton, { commentID: commentID }));
      });
    </script>
  

Elements


    // --- rendering into a root DOM node
    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(<h1>Hello, world</h1>);

    // --- updating
    const elements_root = ReactDOM.createRoot(document.getElementById('elements_root'));
    function tick() {
      const element = (
        <div>
          <h3>It is {new Date().toLocaleTimeString()}</h3>
        </div>
      );
      elements_root.render(element);
    }
    setInterval(tick, 1000);
  

API


    // --- createElement()
    React.createElement(
      type, // tag name string, React component type (class|function), React fragment type
      [props],
      [...children]
    )

    // --- cloneElement()
    // clone and return a new React element using element as the starting point
    // resulting element will have the original element props with the new props merged in shallowly
    // new children will replace existing children
    // key and ref from the original element will be preserved
    React.cloneElement(
      element,
      [props],
      [...children]
    )
    // almost equivalent to:
    // <element.type {...element.props} {...props}>{children}</element.type>
    // introduced as a replacement of the deprecated React.addons.cloneWithProps()

    // --- isValidElement()
    // verifies the object is a React element, returns true or false
    React.isValidElement(object)

    // --- React.Children
    // utilities for dealing with the this.props.children opaque data structure
    React.Children.map(children, fn[(thisArg)]) // returns array
    React.Children.forEach(children, fn[(thisArg)]) // does not return an array
    // number of times that a callback passed to map or forEach would be invoked
    React.Children.count(children)
    // verifies that children has only one child (a React element) and returns it
    // otherwise throws an error
    // does not accept the return value of React.Children.map() because it is an array
    React.Children.only(children)
    // children opaque data structure as a flat array with keys assigned to each child
    React.Children.toArray(children)
  

Component / Props / State


    // JS function - simplest way to define a component
    function Welcome(props) {
      return <h3>Hello, {props.name}</h3>;
    }
    const Example = (props) => {
      // You can use Hooks here!
      return <div />;
    }
    // using ES6 class, equivalent from Reacts point of view
    class Welcome extends React.Component {
      render() {
        return <h3>Hello, {this.props.name}</h3>;
      }
    }

    const element = <Welcome name="Andrei" />; // represent user-defined components
    const comprops_root = ReactDOM.createRoot(document.getElementById('comprops_root'));
    comprops_root.render(element);

    // render many times
    function App() {
      return (
        <div>
          <Welcome name="Andrei" />
          <Welcome name="John" />
          <Welcome name="Leon" />
        </div>
      );
    }
    const comprops_root = ReactDOM.createRoot(document.getElementById('comprops_root'));
    comprops_root.render(<App />);
  

Control props & State reducers


    // Control props - allow complete control over state from outside the component
    // require that the consumer completely manage state themselves
    // means must have a class component with state and change handlers to update that state
    class Example extends React.Component {
      state = {on: false, inputValue: 'off'};
      handleToggle = on => {
        this.setState({on, inputValue: on ? 'on' : 'off'});
      }
      handleChange = ({target: {value}}) => {
        if (value === 'on') {
          this.setState({on: true});
        } else if (value === 'off') {
          this.setState({on: false});
        }
        this.setState({inputValue: value});
      }
      render() {
        const {on} = this.state;
        return (
          <div>
            {/* using the "value" control prop exposed by the input */}
            <input value={this.state.inputValue} onChange={this.handleChange} />
            {/* using the "on" control prop exposed by the Toggle component */}
            <Toggle on={on} onToggle={this.handleToggle} />
          </div>
        );
      }
    }

    // State reducers - do not have to manage the component state themselves
    // they can manage some of their own state as needed
    class Example extends React.Component {
      initialState = {timesClicked: 0};
      state = this.initialState;
      handleToggle = (...args) => {
        this.setState(({timesClicked}) => ({
          timesClicked: timesClicked + 1,
        }));
      }
      handleReset = (...args) => {
        this.setState(this.initialState);
      }
      toggleStateReducer = (state, changes) => {
        if (this.state.timesClicked >= 4) {
          return {...changes, on: false};
        }
        return changes;
      }
      render() {
        const {timesClicked} = this.state;
        return (
          <div>
            <Toggle
              stateReducer={this.toggleStateReducer}
              onToggle={this.handleToggle}
              onReset={this.handleReset}
            />
            {timesClicked > 4 ? (
              <div>Whoa, you clicked too much!</div>
            ) : (
              <div>Click count: {timesClicked}</div>
            )}
          </div>
        )
      }
    }
  
De/Compose Component

    function Avatar(props) {
      return (
        <img className="Avatar"
          src={props.user.avatarUrl}
          alt={props.user.name}
        />
      );
    }
    function UserInfo(props) {
      return (
        <div className="UserInfo">
          <Avatar user={props.user} />
          <div className="UserInfo-name">
            {props.user.name}
          </div>
        </div>
      );
    }
    function Comment(props) {
      return (
        <div className="Comment">
          <UserInfo user={props.author} />
          <div className="Comment-text">
            {props.text}
          </div>
          <div className="Comment-date">
            {formatDate(props.date)}
          </div>
        </div>
      );
    }
    const comment = {
      date: new Date(),
      text: 'Lets React!',
      author: {
        name: 'Hello Andrei',
        avatarUrl: '../images/colorpicker.gif',
      },
    };
    const comprops_2_root = ReactDOM.createRoot(document.getElementById('comprops_2_root'));
    comprops_2_root.render(
      <Comment
        date={comment.date}
        text={comment.text}
        author={comment.author}
      />
    );

    // --- instead of
    function Comment(props) {
      return (
        <div className="Comment">
          <div className="UserInfo">
            <img className="Avatar"
              src={props.author.avatarUrl}`
              alt={props.author.name}
            />
            <div className="UserInfo-name">
              {props.author.name}
            </div>
          </div>
          <div className="Comment-text">
            {props.text}
          </div>
          <div className="Comment-date">
            {formatDate(props.date)}
          </div>
        </div>
      );
    }

    function formatDate(date) {
      return date.toLocaleDateString();
    }
  
Function to Class , Props to State

    function Clock(props) {
      return (
        <div>
          <h2>It is {props.date.toLocaleTimeString()}.</h2>
        </div>
      );
    }

    class Clock extends React.Component {
      render() {
        return (
          <div>
            <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }

    class Clock extends React.Component {
      constructor(props) {
        super(props);
        this.state = {date: new Date()};
      }
      render() {
        return (
          <div>
            <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
          </div>
        );
      }
    }

    const root = ReactDOM.createRoot(document.getElementById('root'));
    root.render(<Clock />);

    // --- pass local state down as props
    <h2>It is {this.state.date.toLocaleTimeString()}</h2>
    ...
    <FormattedDate date={this.state.date} />
  
setState(updater [,callback])

    class Clock extends React.Component {
      constructor(props) {
        super(props);
        this.state = {date: new Date(), counter: 0};
      }
      componentDidMount() {
        this.timerID = setInterval(
          () => this.tick(),
          1000
        );
      }
      componentWillUnmount() {
        clearInterval(this.timerID);
      }
      tick() {
        // --- simple setState
        // this.setState({
        //   date: new Date()
        // });
        // --- second form, to use state and props together
        this.setState(
          // previous state (first argument)
          // props at the time the update is applied (second argument)
          (state, props) => ({
          // function(state, props) {
            date: new Date(),
            // counter: state.counter + 1
            counter: state.counter + props.increment
          // }
        }));
      }
      render() {
        return (
          <div>
            <h3>It is {this.state.date.toLocaleTimeString()}</h3>
            <h3>Counter is {this.state.counter}</h3>
          </div>
        );
      }
    }
    const comprops_3_root = ReactDOM.createRoot(document.getElementById('comprops_3_root'));
    comprops_3_root.render(<Clock increment={7}/>);

    // --- update with separate setState() calls
    // ...
      constructor(props) {
        super(props);
        this.state = {
          posts: [],
          comments: []
        };
      }
      componentDidMount() {
        fetchPosts().then(response => {
          this.setState({
            posts: response.posts
          });
        });
        fetchComments().then(response => {
          this.setState({
            comments: response.comments
          });
        });
      }
    // ...
  

API


    // --- React.Component
    class Greeting extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }

    // --- React.PureComponent
    // implements shouldComponentUpdate() which shallowly compares the objects
    // and skips prop updates for the whole component subtree,
    // make sure all the children components are also "pure".
    // only extend PureComponent when you expect to have simple props and state,
    // or use forceUpdate() when you know deep data structures have changed
    // or consider using immutable objects to facilitate fast comparisons of nested data

    // --- React.memo - HOC, similar to React.PureComponent
    // but for function components instead of classes
    // which renders the same result given the same props
    // only shallowly compare complex objects in the props object
    const MyComponent = React.memo(function MyComponent(props) {
      /* render using props */
    });
    // provide a custom comparison function as the second argument
    function MyComponent(props) {
      /* render using props */
    }
    function areEqual(prevProps, nextProps) {
      /*
      return true if passing nextProps to render would return
      the same result as passing prevProps to render,
      otherwise return false
      */
    }
    export default React.memo(MyComponent, areEqual);
  

Lifecycle


    constructor(props) {
      super(props);
      this.handleClick = this.handleClick.bind(this);
      // dont call this.setState() here ! assign the initial state
      this.state = { counter: 0 };
      // dont do this !!!
      this.state = { color: props.color };
    }
  

    class ScrollingList extends React.Component {
      constructor(props) {
        super(props);
        this.listRef = React.createRef();
      }
      getSnapshotBeforeUpdate(prevProps, prevState) {
        // are we adding new items to the list?
        // capture the scroll position so we can adjust scroll later
        if (prevProps.list.length < this.props.list.length) {
          const list = this.listRef.current;
          return list.scrollHeight - list.scrollTop;
        }
        return null;
      }
      componentDidUpdate(prevProps, prevState, snapshot) {
        // if we have a snapshot value, we just added new items
        // adjust scroll so these new items dont push the old ones out of view
        // (snapshot here is the value returned from getSnapshotBeforeUpdate)
        if (snapshot !== null) {
          const list = this.listRef.current;
          list.scrollTop = list.scrollHeight - snapshot;
        }
      }
      render() {
        return (
          <div ref={this.listRef}>{ /* ...contents... */ }</div>
        );
      }
    }
  

    componentDidUpdate(prevProps) {
      // typical usage (dont forget to compare props):
      if (this.props.userID !== prevProps.userID) {
        this.fetchData(this.props.userID);
      }
    }
  

    class ErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { hasError: false };
      }
      static getDerivedStateFromError(error) {
        // update state so the next render will show the fallback UI
        return { hasError: true };
      }
      componentDidCatch(error, info) {
        // Example "componentStack":
        //   in ComponentThatThrows (created by App)
        //   in ErrorBoundary (created by App)
        //   in div (created by App)
        //   in App
        logComponentStackToMyService(info.componentStack);
      }
      render() {
        if (this.state.hasError) {
          // you can render any custom fallback UI
          return <h1>Something went wrong.</h1>;
        }
        return this.props.children;
      }
    }
  

Events , this


    function ActionLink() {
      function handleClick(e) {
        e.preventDefault();
        console.log('The link was clicked.');
      }
      return ( <a href="#" onClick={handleClick}>Click me</a> );
    }
    class Toggle extends React.Component {
      constructor(props) {
        super(props);
        this.state = {isToggleOn: true};
        // necessary, to make "this" work in the callback
        this.handleClick = this.handleClick.bind(this);
      }
      handleClick() {
        this.setState(state => ({ isToggleOn: !state.isToggleOn }));
      }

      // experimental syntax
      // bound "this" within handleClick without help of construtor
      // enabled by default in Create React App
      handleClick = () => { console.log('this is:', this); }

      render() {
        return (
          <button onClick={this.handleClick}>
            {this.state.isToggleOn ? 'ON' : 'OFF'}
          </button>
        );
      }
    }
    const e_root = ReactDOM.createRoot(document.getElementById('e_root'));
    e_root.render(<Toggle />);
  

    // --- passing params
    const A = 65; // ASCII character code
    class Alphabet extends React.Component {
      constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
        this.state = {
          justClicked: null,
          letters: Array.from(
            {length: 26},
            (_, i) => String.fromCharCode(A + i)
          )
        };
      }
      handleClick(letter) { this.setState({ justClicked: letter }); }
      // or with data-.
      handleClick(e) {
        this.setState({ justClicked: e.target.dataset.letter });
      }
      render() {
        return (
          <div>
            Click on letter in list, last clicked: {this.state.justClicked}
            <br />
            <ul>
              {this.state.letters.map(letter =>
                <li key={letter}
                  onClick={() => this.handleClick(letter)}
                  /* OR with data-. */
                  data-letter={letter} onClick={this.handleClick}
                >
                  {letter}
                </li>
              )}
            </ul>
          </div>
        )
      }
    }
  
SyntheticEvent properties

    bubbles
    cancelable
    currentTarget
    defaultPrevented
    eventPhase
    isTrusted
    DOMEvent nativeEvent
    preventDefault()
    isDefaultPrevented()
    stopPropagation()
    isPropagationStopped()
    target
    timeStamp
    type

    // --- CLIPBOARD
    onCopy onCut onPaste
    DOMDataTransfer clipboardData
    // --- COMPOSITION
    onCompositionEnd onCompositionStart onCompositionUpdate
    data
    // --- KEYBOARD
    onKeyDown onKeyPress onKeyUp
    // properties
    altKey ctrlKey shiftKey metaKey
    charCode
    getModifierState(key)
    key
    keyCode
    locale
    location
    repeat
    which
    // --- FOCUS
    onFocus onBlur
    relatedTarget
    // --- FORM
    onChange onInput onInvalid onSubmit
    // --- MOUSE
    onClick onContextMenu onDoubleClick
    onDrag onDragEnd onDragEnter onDragExit
    onDragLeave onDragOver onDragStart onDrop
    onMouseDown onMouseEnter onMouseLeave
    onMouseMove onMouseOut onMouseOver onMouseUp
    // properties
    altKey ctrlKey shiftKey metaKey
    button
    buttons
    clientX clientY
    getModifierState(key)
    pageX pageY
    relatedTarget
    screenX screenY
    // --- POINTER
    onPointerDown onPointerMove onPointerUp onPointerCancel
    onGotPointerCapture onLostPointerCapture onPointerEnter
    onPointerLeave onPointerOver onPointerOut
    // properties
    pointerId
    width height
    pressure
    tangentialPressure
    tiltX tiltY twist
    pointerType
    isPrimary
    // --- SELECTION
    onSelect
    // --- TOUCH
    onTouchCancel onTouchEnd onTouchMove onTouchStart
    // properties
    altKey ctrlKey shiftKey metaKey
    changedTouches
    getModifierState(key)
    targetTouches
    touches
    // --- UI
    onScroll
    // properties
    detail
    view
    // --- WHEEL
    onWheel
    // properties
    deltaMode
    deltaX deltaY deltaZ
    // --- MEDIA
    onAbort onCanPlay onCanPlayThrough onDurationChange
    onEmptied onEncrypted onEnded onError onLoadedData
    onLoadedMetadata onLoadStart onPause onPlay onPlaying
    onProgress onRateChange onSeeked onSeeking onStalled
    onSuspend onTimeUpdate onVolumeChange onWaiting
    // --- IMAGE
    onLoad onError
    // --- ANIMATION
    onAnimationStart onAnimationEnd onAnimationIteration
    // properties
    animationName
    pseudoElement
    elapsedTime
    // --- TRANSITION
    onTransitionEnd
    // properties
    propertyName
    pseudoElement
    elapsedTime
    // --- OTHER, DETAILS ELEMENT
    onToggle
  
prevent frequent function calls

    // --- throttle
    import throttle from 'lodash.throttle';
    class LoadMoreButton extends React.Component {
      constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
        this.handleClickThrottled = throttle(this.handleClick, 1000);
      }
      componentWillUnmount() {
        this.handleClickThrottled.cancel();
      }
      render() {
        return <button onClick={this.handleClickThrottled}>Load More</button>;
      }
      handleClick() {
        this.props.loadMore();
      }
    }

    // --- debounce
    import debounce from 'lodash.debounce';
    class Searchbox extends React.Component {
      constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
        this.emitChangeDebounced = debounce(this.emitChange, 250);
      }
      componentWillUnmount() {
        this.emitChangeDebounced.cancel();
      }
      render() {
        return (
          <input
            type="text"
            onChange={this.handleChange}
            placeholder="Search..."
            defaultValue={this.props.value}
          />
        );
      }
      handleChange(e) {
        // React pools events, so we read the value before debounce.
        // Alternately we could call `event.persist()` and pass the entire event.
        // For more info see reactjs.org/docs/events.html#event-pooling
        this.emitChangeDebounced(e.target.value);
      }
      emitChange(value) {
        this.props.onChange(value);
      }
    }

    // --- requestAnimationFrame
    import rafSchedule from 'raf-schd';
    class ScrollListener extends React.Component {
      constructor(props) {
        super(props);
        this.handleScroll = this.handleScroll.bind(this);
        // Create a new function to schedule updates.
        this.scheduleUpdate = rafSchedule(
          point => this.props.onScroll(point)
        );
      }
      handleScroll(e) {
        // When we receive a scroll event, schedule an update.
        // If we receive many updates within a frame, we'll only publish the latest value.
        this.scheduleUpdate({ x: e.clientX, y: e.clientY });
      }
      componentWillUnmount() {
        // Cancel any pending updates since we're unmounting.
        this.scheduleUpdate.cancel();
      }
      render() {
        return (
          <div
            style={{ overflow: 'scroll' }}
            onScroll={this.handleScroll}
          >
            <img src="/my-huge-image.jpg" />
          </div>
        );
      }
    }
  

Conditional Rendering


    function UserGreeting(props) { return <h1>Welcome back!</h1>; }
    function GuestGreeting(props) { return <h1>Please sign up.</h1>; }
    function Greeting(props) {
      const isLoggedIn = props.isLoggedIn;
      if (isLoggedIn) { return <UserGreeting />; }
      return <GuestGreeting />;
    }
    function LoginButton(props) {
      return (
        <button onClick={props.onClick}>
          Login
        </button>
      );
    }
    function LogoutButton(props) {
      return (
        <button onClick={props.onClick}>
          Logout
        </button>
      );
    }
    class LoginControl extends React.Component {
      constructor(props) {
        super(props);
        this.handleLoginClick = this.handleLoginClick.bind(this);
        this.handleLogoutClick = this.handleLogoutClick.bind(this);
        this.state = {isLoggedIn: false};
      }
      handleLoginClick() { this.setState({isLoggedIn: true}); }
      handleLogoutClick() { this.setState({isLoggedIn: false}); }
      render() {
        const isLoggedIn = this.state.isLoggedIn;
        let button;
        if (isLoggedIn) {
          button = <LogoutButton onClick={this.handleLogoutClick} />;
        } else {
          button = <LoginButton onClick={this.handleLoginClick} />;
        }
        return (
          <div>
            <Greeting isLoggedIn={isLoggedIn} />
            {button}
          </div>
        );
      }
    }
    const cond_1 = ReactDOM.createRoot(document.getElementById('cond_1'));
    cond_1.render(<LoginControl />);
  
inline "IF" with logical "&&" and ternary operators

    function Mailbox(props) {
      const unreadMessages = props.unreadMessages;
      return (
        <div>
          {unreadMessages.length > 0 &&
            <h2>
              You have {unreadMessages.length} unread messages.
            </h2>
          }
        </div>
      );
    }
    const messages = ['React', 'Re: React', 'Re:Re: React'];
    const cond_2 = ReactDOM.createRoot(document.getElementById('cond_2'));
    cond_2.render(<Mailbox unreadMessages={messages} />);

    // ...
    render() {
      const isLoggedIn = this.state.isLoggedIn;
      return (
        <div>
          The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
        </div>
      );
    }
    // ...
    render() {
      const isLoggedIn = this.state.isLoggedIn;
      return (
        <div>
          {isLoggedIn ? (
            <LogoutButton onClick={this.handleLogoutClick} />
          ) : (
            <LoginButton onClick={this.handleLoginClick} />
          )}
        </div>
      );
    }
    // ...
  
preventing component from rendering (return "null")

    function WarningBanner(props) {
      if (!props.warn) { return null; }
      return (
        <div className="warning">
          Warning!
        </div>
      );
    }
    class Page extends React.Component {
      constructor(props) {
        super(props);
        this.state = {showWarning: true};
        this.handleToggleClick = this.handleToggleClick.bind(this);
      }
      handleToggleClick() {
        this.setState(state => ({
          showWarning: !state.showWarning
        }));
      }
      render() {
        return (
          <div>
            <button onClick={this.handleToggleClick}>
              {this.state.showWarning ? 'Hide' : 'Show'}
            </button>
            <WarningBanner warn={this.state.showWarning} />
          </div>
        );
      }
    }
    const cond_3 = ReactDOM.createRoot(document.getElementById('cond_3'));
    cond_3.render(<Page />);
  

Lists/Keys


    const numbers = [1, 2, 3, 4, 5];
    const listItems = numbers.map((number) =>
      <li>{number}</li>
    );
    const lk_root = ReactDOM.createRoot(document.getElementById('lk_root'));
    lk_root.render(<ul>{listItems}</ul>);
    // --- OR
    function NumberList(props) {
      const numbers = props.numbers;
      const listItems = numbers.map((number) =>
        <li key={number.toString()}>
          {number}
        </li>
      );
      return (
        <ul>{listItems}</ul>
      );
      // --- OR
      return (
        <ul>
          {numbers.map((number) =>
            <ListItem key={number.toString()}
                      value={number} />
          )}
        </ul>
      );
    }
    const lk_root = ReactDOM.createRoot(document.getElementById('lk_root'));
    lk_root.render(<NumberList numbers={numbers} />);

    // ...
    const todoItems = todos.map((todo) =>
      <li key={todo.id}>
        {todo.text}
      </li>
    );
    // ...
    // only do this if items have no stable IDs !!!
    const todoItems = todos.map((todo, index) =>
      <li key={index}>
        {todo.text}
      </li>
    );
    // ...

    // --- keys must only be unique among siblings
    function Blog(props) {
      const sidebar = (
        <ul>
          {props.posts.map((post) =>
            <li key={post.id}>
              {post.title}
            </li>
          )}
        </ul>
      );
      const content = props.posts.map((post) =>
        <div key={post.id}>
          <h3>{post.title}</h3>
          <p>{post.content}</p>
        </div>
      );
      return (
        <div>
          {sidebar}
          <hr />
          {content}
        </div>
      );
    }
    const posts = [
      {id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
      {id: 2, title: 'Installation', content: 'You can install React from npm.'}
    ];
    const lk_root = ReactDOM.createRoot(document.getElementById('lk_root'));
    lk_root.render(<Blog posts={posts} />);

    // ...
    // can read props.id, but not props.key
    const content = posts.map((post) =>
      <Post
        key={post.id}
        id={post.id}
        title={post.title} />
    );
    // ...
  
Example

    const ToDo = props => (
      <tr>
        <td>
          <label>{props.id}</label>
        </td>
        <td>
          <input />
        </td>
        <td>
          <label>{props.createdAt.toTimeString()}</label>
        </td>
      </tr>
    );
    class ToDoList extends React.Component {
      constructor() {
        super();
        const date = new Date();
        const toDoCounter = 1;
        this.state = {
          list: [
            {
              id: toDoCounter,
              createdAt: date,
            },
          ],
          toDoCounter: toDoCounter,
        };
      }
      sortByEarliest() {
        const sortedList = this.state.list.sort((a, b) => {
          return a.createdAt - b.createdAt;
        });
        this.setState({
          list: [...sortedList],
        });
      }
      sortByLatest() {
        const sortedList = this.state.list.sort((a, b) => {
          return b.createdAt - a.createdAt;
        });
        this.setState({
          list: [...sortedList],
        });
      }
      addToEnd() {
        const date = new Date();
        const nextId = this.state.toDoCounter + 1;
        const newList = [
          ...this.state.list,
          {id: nextId, createdAt: date},
        ];
        this.setState({
          list: newList,
          toDoCounter: nextId,
        });
      }
      addToStart() {
        const date = new Date();
        const nextId = this.state.toDoCounter + 1;
        const newList = [
          {id: nextId, createdAt: date},
          ...this.state.list,
        ];
        this.setState({
          list: newList,
          toDoCounter: nextId,
        });
      }
      render() {
        return (
          <div>
            <code>key=id</code>
            <br />
            <button onClick={this.addToStart.bind(this)}>
              Add New to Start
            </button>
            <button onClick={this.addToEnd.bind(this)}>
              Add New to End
            </button>
            <button onClick={this.sortByEarliest.bind(this)}>
              Sort by Earliest
            </button>
            <button onClick={this.sortByLatest.bind(this)}>
              Sort by Latest
            </button>
            <table>
              <tr>
                <th>ID</th>
                <th />
                <th>created at</th>
              </tr>
              {this.state.list.map((todo, index) => (
                <ToDo key={todo.id} {...todo} />
              ))}
            </table>
          </div>
        );
      }
    }
    const list_example_root = ReactDOM.createRoot(document.getElementById('list_example_root'));
    list_example_root.render(<ToDoList />);
  
Pagination

    class TodoApp extends React.Component {
      constructor() {
        super();
        this.state = {
          todos: ['a','b','c','d','e','f','g','h','i','j','k'],
          currentPage: 1,
          todosPerPage: 3
        };
        this.handleClick = this.handleClick.bind(this);
      }
      handleClick(event) {
        this.setState({
          currentPage: Number(event.target.id)
        });
      }
      render() {
        const { todos, currentPage, todosPerPage } = this.state;
        // Logic for displaying todos
        const indexOfLastTodo = currentPage * todosPerPage;
        const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
        const currentTodos = todos.slice(indexOfFirstTodo, indexOfLastTodo);
        const renderTodos = currentTodos.map((todo, index) => {
          return <li key={index}>{todo}</li>;
        });
        // Logic for displaying page numbers
        const pageNumbers = [];
        for (let i = 1; i <= Math.ceil(todos.length / todosPerPage); i++) {
          pageNumbers.push(i);
        }
        const renderPageNumbers = pageNumbers.map(number => {
          return (
            <span
              key={number}
              id={number}
              onClick={this.handleClick}
            >
              ({number})
            </span>
          );
        });
        return (
          <div>
            <div>Click on numbers</div>
            <div>{renderPageNumbers}</div>
            <ul>
              {renderTodos}
            </ul>
          </div>
        );
      }
    }
    const list_pagination_root = ReactDOM.createRoot(document.getElementById('list_pagination_root'));
    list_pagination_root.render(<TodoApp />);
  

Forms


    class NameForm extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          working: false,
          gender: 'male',
          input_text: 'Andrei',
          input_textarea: 'Some text here ...',
          select_age: 35,
          select_hobby: ['sport','tech'] // create selection scenario...
        };
        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
      }

      handleChange(event) {
        // this.setState({value: event.target.value.toUpperCase()});
        // or, for multiple inputs:
        const target = event.target;
        const value = (target.type === 'checkbox') ? target.checked : target.value;
        const name = target.name;
        this.setState({
          [name]: value
        });
        // equivalent to this ES5 code:
        // var partialState = {};
        // partialState[name] = value;
        // this.setState(partialState);
      }

      handleSubmit(event) {
        event.preventDefault();
        const output =
          "working: " + this.state.working.toString() + "\n" +
          "gender: " + this.state.gender.toString() + "\n" +
          "input_text: " + this.state.input_text.toString() + "\n" +
          "input_textarea: " + this.state.input_textarea.toString() + "\n" +
          "select_hobby: " + this.state.select_hobby.toString() + "\n" +
          "select_age: " + this.state.select_age.toString();
        alert('Values:\n' + output);
      }

      render() {
        return (
          <form onSubmit={this.handleSubmit}>

            Working:
            <input
              name="working"
              type="checkbox"
              checked={this.state.working}
              onChange={this.handleChange}
            />

            Gender:
            <input
              type="radio"
              name="gender"
              value="male"
              checked={this.state.gender === "male"}
              onChange={this.handleChange}
              id="forms_root_male"
            />
            <label htmlFor="forms_root_male">Male</label>
            <input
              type="radio"
              name="gender"
              value="female"
              checked={this.state.gender === "female"}
              onChange={this.handleChange}
              id="forms_root_female"
            />
            <label htmlFor="forms_root_female">Female</label>

            Name:
            <input
              type="text"
              name="input_text"
              value={this.state.input_text}
              onChange={this.handleChange}
            />

            Info:
            <textarea
              name="input_textarea"
              value={this.state.input_textarea}
              onChange={this.handleChange}
            />

            Hobby:
            <select
              multiple={true}
              name="select_hobby"
              value={this.state.select_hobby}
              onChange={this.handleChange}
            >
              <option value="sport">Sport</option>
              <option value="tech">Tech</option>
              <option value="books">Books</option>
              <option value="travel">Travel</option>
            </select>

            Age Range:
            <select
              name="select_age"
              value={this.state.select_age}
              onChange={this.handleChange}
            >
              <option value="18">up to 18</option>
              <option value="25">19-25</option>
              <option value="35">26-35</option>
              <option value="100">36-...</option>
            </select>

          <input type="submit" value="Submit" />

        </form>
        );
      }
    }
    const forms_root = ReactDOM.createRoot(document.getElementById('forms_root'));
    forms_root.render(<NameForm />);

    // --- dangerouslySetInnerHTML
    function createMarkup() {
      return {__html: 'First · Second'};
    }
    function MyComponent() {
      return <div dangerouslySetInnerHTML={createMarkup()} />;
    }
  

uncontrolled component form


    class UncontrolledComponentForm extends React.Component {
      constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.inputName = React.createRef();
        this.inputHobby = React.createRef();
        this.inputFile = React.createRef();
      }
      handleSubmit(event) {
        event.preventDefault();
        const inputFile = (
          this.inputFile.current.files[0] ?
          this.inputFile.current.files[0].name : "[ No File ]"
        );
        alert(
          'submitted: '
          + this.inputName.current.value + ', '
          + this.inputHobby.current.value + ', '
          + inputFile
        );
      }
      render() {
        return (
          <form onSubmit={this.handleSubmit}>
            <label>
              Name:
              <input type="text" ref={this.inputName} />
            </label><br/>
            <label>
              Hobby:
              <input
                defaultValue="Sport"
                type="text"
                ref={this.inputHobby} />
            </label><br/>
            <label>
              Avatar:
              <input type="file" ref={this.inputFile} />
            </label><br/>
            <input type="submit" value="Submit" />
          </form>
        );
      }
    }
    const uc_root = ReactDOM.createRoot(document.getElementById('uc_root'));
    uc_root.render(<UncontrolledComponentForm />);
  

Lifting State


    const scaleNames = {
      c: 'Celsius',
      f: 'Fahrenheit'
    };
    function toCelsius(fahrenheit) {
      return (fahrenheit - 32) * 5 / 9;
    }
    function toFahrenheit(celsius) {
      return (celsius * 9 / 5) + 32;
    }
    function tryConvert(temperature, convert) {
      const input = parseFloat(temperature);
      if (Number.isNaN(input)) {
        return '';
      }
      const output = convert(input);
      const rounded = Math.round(output * 1000) / 1000;
      return rounded.toString();
    }
    function BoilingVerdict(props) {
      if (props.celsius >= 100) {
        return <p>The water would boil</p>;
      }
      return <p>The water would not boil</p>;
    }
    class TemperatureInput extends React.Component {
      constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
      }
      handleChange(e) {
        // send local value to Calculator handler
        this.props.onTemperatureChange(e.target.value);
      }
      render() {
        const temperature = this.props.temperature;
        const scale = this.props.scale;
        return (
          <fieldset>
            <legend>Enter temperature in {scaleNames[scale]}:</legend>
            <input
              value={temperature}
              onChange={this.handleChange} />
          </fieldset>
        );
      }
    }
    class Calculator extends React.Component {
      constructor(props) {
        super(props);
        this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
        this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
        // single “source of truth” for any data that changes
        this.state = {
          temperature: '',
          scale: 'c'
        };
      }
      // will re-render both TemperatureInput when calling their handlers
      handleCelsiusChange(temperature) {
        this.setState({scale: 'c', temperature});
      }
      handleFahrenheitChange(temperature) {
        this.setState({scale: 'f', temperature});
      }
      render() {
        const scale = this.state.scale;
        const temperature = this.state.temperature;
        const celsius =
          scale === 'f' ?
            tryConvert(temperature, toCelsius) : temperature;
        const fahrenheit =
          scale === 'c' ?
            tryConvert(temperature, toFahrenheit) : temperature;
        return (
          <div>
            <TemperatureInput
              scale="c"
              temperature={celsius}
              onTemperatureChange={this.handleCelsiusChange} />
            <TemperatureInput
              scale="f"
              temperature={fahrenheit}
              onTemperatureChange={this.handleFahrenheitChange} />
            <BoilingVerdict
              celsius={parseFloat(celsius)} />
          </div>
        );
      }
    }
    const ls_root = ReactDOM.createRoot(document.getElementById('ls_root'));
    ls_root.render(<Calculator />);
  

Composition

props.children - contains anything between component tags

    function FancyBorder(props) {
      return (
        <div className={'FancyBorder FancyBorder-' + props.color}>
          {props.children}
        </div>
      );
    }
    function WelcomeDialog() {
      return (
        <FancyBorder color="blue">
          <h1 className="Dialog-title">
            Welcome
          </h1>
          <p className="Dialog-message">
            Thank you for visiting our spacecraft!
          </p>
        </FancyBorder>
      );
    }
  
pass React elements as props like any other data

    function SplitPane(props) {
      return (
        <div className="SplitPane">
          <div className="SplitPane-left">
            {props.left}
          </div>
          <div className="SplitPane-right">
            {props.right}
          </div>
        </div>
      );
    }
    function App() {
      return (
        <SplitPane
          left={
            <Contacts />
          }
          right={
            <Chat />
          } />
      );
    }
  
more specific component renders a more generic

    function Dialog(props) {
      return (
        <FancyBorder color="blue">
          <h1 className="Dialog-title">
            {props.title}
          </h1>
          <p className="Dialog-message">
            {props.message}
          </p>
        </FancyBorder>
      );
    }
    function WelcomeDialog() {
      return (
        <Dialog
          title="Welcome"
          message="Thank you for visiting our spacecraft!" />
      );
    }
    // --- OR
    function Dialog(props) {
      return (
        <FancyBorder color="blue">
          <h1 className="Dialog-title">
            {props.title}
          </h1>
          <p className="Dialog-message">
            {props.message}
          </p>
          {props.children}
        </FancyBorder>
      );
    }
    class SignUpDialog extends React.Component {
      constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
        this.handleSignUp = this.handleSignUp.bind(this);
        this.state = {login: ''};
      }
      render() {
        return (
          <Dialog
            title="Mars Exploration Program"
            message="How should we refer to you?">
            <input
              value={this.state.login}
              onChange={this.handleChange} />
            <button onClick={this.handleSignUp}>
              Sign Me Up!
            </button>
          </Dialog>
        );
      }
      handleChange(e) {
        this.setState({login: e.target.value});
      }
      handleSignUp() {
        alert(`Welcome aboard, ${this.state.login}!`);
      }
    }
  
composition alternatives

    // pass down the Avatar component itself
    // so that the intermediate components dont need to know
    // about the user or avatarSize props
    function Page(props) {
      const user = props.user;
      const userLink = (
        <Link href={user.permalink}>
          <Avatar user={user} size={props.avatarSize} />
        </Link>
      );
      return <PageLayout userLink={userLink} />;
    }

    // Now, we have:
    <Page user={user} avatarSize={avatarSize} />
    // ... which renders ...
    <PageLayout userLink={...} />
    // ... which renders ...
    <NavigationBar userLink={...} />
    // ... which renders ...
    {props.userLink}

    // pass multiple children,
    // or even have multiple separate "slots" for children
    function Page(props) {
      const user = props.user;
      const content = <Feed user={user} />;
      const topBar = (
        <NavigationBar>
          <Link href={user.permalink}>
            <Avatar user={user} size={props.avatarSize} />
          </Link>
        </NavigationBar>
      );
      return (
        <PageLayout
          topBar={topBar}
          content={content}
        />
      );
    }
  

Context

Dynamic Context

    // --- theme-context.js
    // export
    const themes = {
      light: {
        foreground: '#000000',
        background: '#eeeeee',
      },
      dark: {
        foreground: '#ffffff',
        background: '#222222',
      },
    };
    // export
    const ThemeContextOne = React.createContext(
      themes.dark // default value
    );
    // --- themed-button.js
    // import {ThemeContext} from './theme-context';
    class ThemedButtonOne extends React.Component {
      render() {
        let props = this.props;
        let theme = this.context;
        return (
          <button
            {...props}
            style={{
              backgroundColor: theme.background,
              color: theme.foreground
            }}
          />
        );
      }
    }
    ThemedButtonOne.contextType = ThemeContextOne;
    // export default ThemedButton;
    // --- app.js
    // import {ThemeContextOne, themes} from './theme-context';
    // import ThemedButtonOne from './themed-button';
    // An intermediate component that uses the ThemedButtonOne
    function Toolbar(props) {
      return (
        <ThemedButtonOne onClick={props.changeTheme}>
          Change Theme
        </ThemedButtonOne>
      );
    }
    class ContextAppOne extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          theme: themes.light,
        };
        this.toggleTheme = () => {
          this.setState(state => ({
            theme:
              state.theme === themes.dark
                ? themes.light
                : themes.dark,
          }));
        };
      }
      render() {
        // The ThemedButtonOne button inside the ThemeProvider
        // uses the theme from state while the one outside uses
        // the default dark theme
        return (
          <div>
            <ThemeContextOne.Provider value={this.state.theme}>
              <Toolbar changeTheme={this.toggleTheme} />
            </ThemeContextOne.Provider>
            <div>
            <ThemedButtonOne>
              Default Theme
            </ThemedButtonOne>
            </div>
          </div>
        );
      }
    }
    const context_root_1 = ReactDOM.createRoot(document.getElementById('context_root_1'));
    context_root_1.render(<ContextAppOne />);
  
Updating Context from a Nested Component

    // --- theme-context.js
    // Make sure the shape of the default value passed to
    // createContext matches the shape that the consumers expect!
    // export
    const ThemeContextTwo = React.createContext({
      theme: themes.dark,
      toggleTheme: () => {},
    });
    // --- theme-toggler-button.js
    // import {ThemeContextTwo} from './theme-context';
    function ThemeTogglerButton() {
      // The Theme Toggler Button receives not only the theme
      // but also a toggleTheme function from the context
      return (
        <ThemeContextTwo.Consumer>
          {({theme, toggleTheme}) => (
            <button
              onClick={toggleTheme}
              style={{
                backgroundColor: theme.background,
                color: theme.foreground
              }}>
              Toggle Theme
            </button>
          )}
        </ThemeContextTwo.Consumer>
      );
    }
    // export default ThemeTogglerButton;
    // --- app.js
    // import {ThemeContextTwo, themes} from './theme-context';
    // import ThemeTogglerButton from './theme-toggler-button';
    class ContextAppTwo extends React.Component {
      constructor(props) {
        super(props);
        this.toggleTheme = () => {
          this.setState(state => ({
            theme:
              state.theme === themes.dark
                ? themes.light
                : themes.dark,
          }));
        };
        // State also contains the updater function so it will
        // be passed down into the context provider
        this.state = {
          theme: themes.light,
          toggleTheme: this.toggleTheme,
        };
      }
      render() {
        // The entire state is passed to the provider
        return (
          <ThemeContextTwo.Provider value={this.state}>
            <Content />
          </ThemeContextTwo.Provider>
        );
      }
    }
    function Content() {
      return (
        <div>
          <ThemeTogglerButton />
        </div>
      );
    }
    const context_root_2 = ReactDOM.createRoot(document.getElementById('context_root_2'));
    context_root_2.render(<ContextAppTwo />);
  
Consuming Multiple Contexts

    // Theme context, default to light theme
    const ThemeContextThree = React.createContext('light');
    // Signed-in user context
    const UserContextThree = React.createContext({
      name: 'Guest',
    });
    class ContextAppThree extends React.Component {
      render() {
        const {signedInUser, theme} = this.props;
        // App component that provides initial context values
        return (
          <ThemeContextThree.Provider value={theme}>
            <UserContextThree.Provider value={signedInUser}>
              <Layout />
            </UserContextThree.Provider>
          </ThemeContextThree.Provider>
        );
      }
    }
    function Layout() {
      return (
        <div>
          <Sidebar />
          <Content />
        </div>
      );
    }
    // A component may consume multiple contexts
    function Content() {
      return (
        <ThemeContextThree.Consumer>
          {theme => (
            <UserContextThree.Consumer>
              {user => (
                <ProfilePage user={user} theme={theme} />
              )}
            </UserContextThree.Consumer>
          )}
        </ThemeContextThree.Consumer>
      );
    }
  

Error Boundaries


    class ErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { hasError: false };
      }
      static getDerivedStateFromError(error) {
        // Update state so the next render will show the fallback UI.
        return { hasError: true };
      }
      componentDidCatch(error, info) {
        // You can also log the error to an error reporting service
        logErrorToMyService(error, info);
      }
      render() {
        if (this.state.hasError) {
          // You can render any custom fallback UI
          return <h1>Something went wrong.</h1>;
        }
        return this.props.children;
      }
    }
    // then you can use it as a regular component:
    <ErrorBoundary>
      <MyWidget />
    </ErrorBoundary>

    // --- --- ---

    class ErrorBoundary extends React.Component {
      constructor(props) {
        super(props);
        this.state = { error: null, errorInfo: null };
      }
      componentDidCatch(error, errorInfo) {
        // Catch errors in any components below and re-render with error message
        this.setState({
          error: error,
          errorInfo: errorInfo
        })
        // You can also log error messages to an error reporting service here
      }
      render() {
        if (this.state.errorInfo) {
          // Error path
          return (
            <div>
              <h2>Something went wrong.</h2>
              <details style={{ whiteSpace: 'pre-wrap' }}>
                {this.state.error && this.state.error.toString()}
                <br />
                {this.state.errorInfo.componentStack}
              </details>
            </div>
          );
        }
        // Normally, just render children
        return this.props.children;
      }
    }
    class BuggyCounter extends React.Component {
      constructor(props) {
        super(props);
        this.state = { counter: 0 };
        this.handleClick = this.handleClick.bind(this);
      }
      handleClick() {
        this.setState(({counter}) => ({
          counter: counter + 1
        }));
        // try {
        //   // Do something that could throw
        // } catch (error) {
        //   this.setState({ error });
        // }
      }
      render() {
        if (this.state.counter === 5) {
          // Simulate a JS error
          throw new Error('I crashed!');
        }
        return <h1 onClick={this.handleClick}>{this.state.counter}</h1>;
        // if (this.state.error) {
        //   return <h1>Caught an error.</h1>
        // }
        // return <div onClick={this.handleClick}>Click Me</div>
      }
    }
    function ErrApp() {
      return (
        <div>
          <p>
            <b>
              example of error boundaries in React<br />
              Click on the numbers to increase the counters<br />
              The counter is programmed to throw when it reaches 5<br />
              This simulates a JavaScript error in a component
            </b>
          </p>
          <hr />
          <ErrorBoundary>
            <p>These two counters are inside the same error boundary<br />
            If one crashes, the error boundary will replace both of them.</p>
            <BuggyCounter />
            <BuggyCounter />
          </ErrorBoundary>
          <hr />
          <p>These two counters are each inside of their own error boundary<br />
          So if one crashes, the other is not affected.</p>
          <ErrorBoundary><BuggyCounter /></ErrorBoundary>
          <ErrorBoundary><BuggyCounter /></ErrorBoundary>
        </div>
      );
    }
    const err_root = ReactDOM.createRoot(document.getElementById('err_root'));
    err_root.render(<ErrApp />);
  

Ref


    // create ref
    class MyComponent extends React.Component {
      constructor(props) {
        super(props);
        this.myRef = React.createRef();
        const node = this.myRef.current; // reference to the node
      }
      render() {
        return <div ref={this.myRef} />;
      }
    }

    // --- adding a ref to a dom element
    class CustomTextInput extends React.Component {
      constructor(props) {
        super(props);
        // create a ref to store the textInput DOM element
        this.textInput = React.createRef();
        this.focusTextInput = this.focusTextInput.bind(this);
      }
      focusTextInput() {
        // Explicitly focus the text input using the raw DOM API
        // Note: we are accessing "current" to get the DOM node
        this.textInput.current.focus();
      }
      render() {
        // tell React that we want to associate the input ref
        // with the "textInput" that we created in the constructor
        return (
          <div>
            <input
              type="text"
              ref={this.textInput} />
            <input
              type="button"
              value="Focus the text input"
              onClick={this.focusTextInput}
            />
          </div>
        );
      }
    }

    // --- adding a ref to a class component
    // simulate click immediately after mounting
    // only works if CustomTextInput is declared as a class
    class AutoFocusTextInput extends React.Component {
      constructor(props) {
        super(props);
        this.textInput = React.createRef();
      }
      componentDidMount() {
        this.textInput.current.focusTextInput();
      }
      render() {
        return (
          <CustomTextInput ref={this.textInput} />
        );
      }
    }

    // --- use the ref attribute inside a function component
    function CustomTextInput(props) {
      // textInput must be declared here so the ref can refer to it
      let textInput = React.createRef();
      function handleClick() {
        textInput.current.focus();
      }
      return (
        <div>
          <input
            type="text"
            ref={textInput} />
          <input
            type="button"
            value="Focus the text input"
            onClick={handleClick}
          />
        </div>
      );
    }

    // --- add a wrapper DOM node in component and attach a ref directly to it
    class MyComponent extends React.Component {
      constructor(props) {
        super(props);
        this.wrapper = React.createRef();
      }
      render() {
        return <div ref={this.wrapper}>{this.props.children}</div>;
      }
    }
  
forwarding refs

    // --- to DOM components
    // 5 - when the ref is attached, ref.current will point to the button DOM node
    const FancyButton = React.forwardRef((props, ref) => (
      // 3 - ref is passed
      // 4 - forward ref down to button by specifying it as a JSX attribute
      <button ref={ref} className="FancyButton">
        {props.children}
      </button>
    ));
    // You can now get a ref directly to the DOM button:
    const ref = React.createRef(); // 1 - create a React ref
    // 2 - pass our ref down to FancyButton by specifying it as a JSX attribute
    <FancyButton ref={ref}>Click me!</FancyButton>;

    // --- in higher-order components
    function logProps(Component) {
      class LogProps extends React.Component {
        componentDidUpdate(prevProps) {
          console.log('old props:', prevProps);
          console.log('new props:', this.props);
        }
        render() {
          const {forwardedRef, ...rest} = this.props;

          // Assign the custom prop "forwardedRef" as a ref
          return <Component ref={forwardedRef} {...rest} />;
        }
      }
      // Note the second param "ref" provided by React.forwardRef.
      // We can pass it along to LogProps as a regular prop, e.g. "forwardedRef"
      // And it can then be attached to the Component.
      return React.forwardRef((props, ref) => {
        return <LogProps {...props} forwardedRef={ref} />;
      });
    }
    // ... log all props that get passed to our "fancy button" component
    class FancyButton extends React.Component {
      focus() {
        // ...
      }
      // ...
    }
    // Rather than exporting FancyButton, we export LogProps
    // It will render a FancyButton though
    export default logProps(FancyButton);

    // --- displaying a custom name in DevTools
    const WrappedComponent = React.forwardRef((props, ref) => {
      return <LogProps {...props} forwardedRef={ref} />;
    });
    // include the render function name
    const WrappedComponent = React.forwardRef(
      function myFunction(props, ref) {
        return <LogProps {...props} forwardedRef={ref} />;
      }
    );
    // set the function displayName property to include the wrapping component
    function logProps(Component) {
      class LogProps extends React.Component {
        // ...
      }
      function forwardRef(props, ref) {
        return <LogProps {...props} forwardedRef={ref} />;
      }
      // Give this component a more helpful display name in DevTools.
      // e.g. "ForwardRef(logProps(MyComponent))"
      const name = Component.displayName || Component.name;
      forwardRef.displayName = `logProps(${name})`;
      return React.forwardRef(forwardRef);
    }

    // --- ref forwarding alternatives before 16.3
    function CustomTextInput(props) {
      return (
        <div>
          <input ref={props.inputRef} />
        </div>
      );
    }
    function Parent(props) {
      return (
        <div>
          My input: <CustomTextInput inputRef={props.inputRef} />
        </div>
      );
    }
    class Grandparent extends React.Component {
      constructor(props) {
        super(props);
        this.inputElement = React.createRef();
      }
      render() {
        return (
          <Parent inputRef={this.inputElement} />
        );
      }
    }
  
callback refs

    // using the ref callback to store a reference to a DOM node in an instance property
    class CustomTextInput extends React.Component {
      constructor(props) {
        super(props);
        this.textInput = null;
        this.setTextInputRef = element => {
          this.textInput = element;
        };
        this.focusTextInput = () => {
          // Focus the text input using the raw DOM API
          if (this.textInput) this.textInput.focus();
        };
      }
      componentDidMount() {
        // autofocus the input on mount
        this.focusTextInput();
      }
      render() {
        // Use the "ref" callback to store a reference to the text input DOM
        // element in an instance field (for example, this.textInput).
        return (
          <div>
            <input
              type="text"
              ref={this.setTextInputRef}
            />
            <input
              type="button"
              value="Focus the text input"
              onClick={this.focusTextInput}
            />
          </div>
        );
      }
    }

    // --- pass callback refs between components, like objects ref
    // this.inputElement in Parent will be set
    // to the DOM node corresponding to the input element in the CustomTextInput
    function CustomTextInput(props) {
      // pass same function as a special ref attribute to the input
      return (
        <div>
          <input ref={props.inputRef} />
        </div>
      );
    }
    class Parent extends React.Component {
      render() {
        // pass ref callback as an inputRef prop to the CustomTextInput
        return (
          <CustomTextInput
            inputRef={el => this.inputElement = el}
          />
        );
      }
    }
  

Fragments


    class FragmentsTable extends React.Component {
      render() {
        return (
          <table>
          <tbody>
            <tr>
              <FragmentsColumns />
            </tr>
          </tbody>
          </table>
        );
      }
    }
    class FragmentsColumns extends React.Component {
      render() {
        return (
          <React.Fragment>
            <td>Hello</td>
            <td>World</td>
          </React.Fragment>
        );
      }
    }
    const fragments_root = ReactDOM.createRoot(document.getElementById('fragments_root'));
    fragments_root.render(<FragmentsTable />);

    // --- keyed fragments
    function Glossary(props) {
      return (
        <dl>
          {props.items.map(item => (
            // Without the `key`, React will fire a key warning
            <React.Fragment key={item.id}>
              <dt>{item.term}</dt>
              <dd>{item.description}</dd>
            </React.Fragment>
          ))}
        </dl>
      );
    }
  

HOC


    // This function takes a component...
    function withSubscription(WrappedComponent, selectData) {
      // ...and returns another component...
      return class extends React.Component {
        constructor(props) {
          super(props);
          this.handleChange = this.handleChange.bind(this);
          this.state = {
            data: selectData(DataSource, props)
          };
        }
        componentDidMount() {
          // ... that takes care of the subscription...
          DataSource.addChangeListener(this.handleChange);
        }
        componentWillUnmount() {
          DataSource.removeChangeListener(this.handleChange);
        }
        handleChange() {
          this.setState({
            data: selectData(DataSource, this.props)
          });
        }
        render() {
          // renders the wrapped component with the fresh data
          // pass through any additional props
          return <WrappedComponent data={this.state.data} {...this.props} />;
        }
      };
    }

    const CommentListWithSubscription = withSubscription(
      CommentList,
      (DataSource) => DataSource.getComments()
    );

    const BlogPostWithSubscription = withSubscription(
      BlogPost,
      (DataSource, props) => DataSource.getBlogPost(props.id)
    );
  

Advices


    // --- composition instead of prototyping
    function logProps(WrappedComponent) {
      return class extends React.Component {
        componentWillReceiveProps(nextProps) {
          console.log('Current props: ', this.props);
          console.log('Next props: ', nextProps);
        }
        render() {
          // wraps the input component in a container, without mutating it
          return <WrappedComponent {...this.props} />;
        }
      }
    }

    // --- pass unrelated props through to the wrapped component
    // ...
    render() {
      // filter out extra props that are specific to this HOC
      // and shouldnt be passed through
      const { extraProp, ...passThroughProps } = this.props;
      // inject props into the wrapped component
      // these are usually state values or instance methods
      const injectedProp = someStateOrInstanceMethod;
      // Pass props to wrapped component
      return (
        <WrappedComponent
          injectedProp={injectedProp}
          {...passThroughProps}
        />
      );
    }
    // ...

    // --- maximizing composability
    const CommentWithRelay = Relay.createContainer(Comment, config);
    // OR, instead of doing this...
    const EnhancedComponent = withRouter(connect(commentSelector)(WrappedComponent))
    // ... you can use a function composition utility
    // compose(f, g, h) is the same as (...args) => f(g(h(...args)))
    const enhance = compose(
      // these are both single-argument HOCs
      withRouter,
      connect(commentSelector)
    )
    const EnhancedComponent = enhance(WrappedComponent)

    // --- wrap the display name for easy debugging
    function withSubscription(WrappedComponent) {
      class WithSubscription extends React.Component {/* ... */}
      WithSubscription.displayName =
        `WithSubscription(${getDisplayName(WrappedComponent)})`;
      return WithSubscription;
    }
    function getDisplayName(WrappedComponent) {
      return WrappedComponent.displayName || WrappedComponent.name || 'Component';
    }

    // --- dont use hocs inside the render method
    // ...
    render() {
      // A new version of EnhancedComponent is created on every render
      // EnhancedComponent1 !== EnhancedComponent2
      const EnhancedComponent = enhance(MyComponent);
      // That causes the entire subtree to unmount/remount each time!
      return <EnhancedComponent />;
    }
    // ...

    // --- static methods must be copied over
    function enhance(WrappedComponent) {
      class Enhance extends React.Component {/*...*/}
      // must know exactly which method(s) to copy :(
      Enhance.staticMethod = WrappedComponent.staticMethod;
      return Enhance;
    }
    // OR, use hoist-non-react-statics to automatically copy all non-React static methods
    import hoistNonReactStatic from 'hoist-non-react-statics';
    function enhance(WrappedComponent) {
      class Enhance extends React.Component {/*...*/}
      hoistNonReactStatic(Enhance, WrappedComponent);
      return Enhance;
    }
    // OR, export the static method separately from the component itself
    // Instead of...
    MyComponent.someFunction = someFunction;
    export default MyComponent;
    // ...export the method separately...
    export { someFunction };
    // ...and in the consuming module, import both
    import MyComponent, { someFunction } from './MyComponent.js';
  

Portals


    // These two containers are siblings in the DOM
    const portal_root = document.getElementById('portal_root');
    const portal_modal = document.getElementById('portal_modal');

    class Modal extends React.Component {
      constructor(props) {
        super(props);
        this.el = document.createElement('div');
      }
      componentDidMount() {
        // The portal element is inserted in the DOM tree after
        // the Modal children are mounted, meaning that children
        // will be mounted on a detached DOM node. If a child
        // component requires to be attached to the DOM tree
        // immediately when mounted, for example to measure a
        // DOM node, or uses "autoFocus" in a descendant, add
        // state to Modal and only render the children when Modal
        // is inserted in the DOM tree
        portal_modal.appendChild(this.el);
      }
      componentWillUnmount() {
        portal_modal.removeChild(this.el);
      }
      render() {
        return ReactDOM.createPortal(
          this.props.children,
          this.el,
        );
      }
    }

    class Parent extends React.Component {
      constructor(props) {
        super(props);
        this.state = {clicks: 0};
        this.handleClick = this.handleClick.bind(this);
      }
      handleClick() {
        // This will fire when the button in Child is clicked,
        // updating Parent state, even though button
        // is not direct descendant in the DOM
        this.setState(state => ({
          clicks: state.clicks + 1
        }));
      }
      render() {
        return (
          <div onClick={this.handleClick}>
            <p>Number of clicks: {this.state.clicks}</p>
            <p>button is not a child of the div with the onClick handler</p>
            <Modal>
              <Child />
            </Modal>
          </div>
        );
      }
    }

    function Child() {
      // The click event on this button will bubble up to parent,
      // because there is no 'onClick' attribute defined
      return (
        <div className="modal">
          <button>Click</button>
        </div>
      );
    }

    const portal_root_root = ReactDOM.createRoot(portal_root);
    portal_root_root.render(<Parent />);
  

Render Props


    class Cat extends React.Component {
      render() {
        const mouse = this.props.mouse;
        return (
          <img
            src="../images/cat.jpg"
            style={{ position: 'absolute', left: mouse.x, top: mouse.y }}
          />
        );
      }
    }
    class Mouse extends React.Component {
      constructor(props) {
        super(props);
        this.handleMouseMove = this.handleMouseMove.bind(this);
        this.state = { x: 0, y: 0 };
      }
      handleMouseMove(event) {
        this.setState({
          // allign to scroll offset ...
          x: event.clientX,
          y: event.clientY
        });
      }
      render() {
        // dynamically determine what to render
        // instead of providing a static representation of what Mouse renders
        return (
          <div
            className="h-30 w_100"
            onMouseMove={this.handleMouseMove}
            onTouchMove={this.handleMouseMove}
          >
            {this.props.render(this.state)}
          </div>
        );
      }
    }
    class MouseTracker extends React.Component {
      renderTheCat(mouse) {
        return <Cat mouse={mouse}/>;
      }
      render() {
        return (
          <div>
            <Mouse render={this.renderTheCat}/>
          </div>
        );
      }
    }
    // const render_prop_root = ReactDOM.createRoot(document.getElementById('render_prop_root'));
    // render_prop_root.render(<MouseTracker />);

    // --- HOC with render prop
    function withMouse(Component) {
      return class extends React.Component {
        render() {
          return (
            <Mouse render={mouse => (
              <Component {...this.props} mouse={mouse} />
            )}/>
          );
        }
      }
    }
    const CatWithMouse = withMouse(Cat);
    const render_prop_root = ReactDOM.createRoot(document.getElementById('render_prop_root'));
    render_prop_root.render(<CatWithMouse/>);

    // --- use the children prop, instead of render
    <Mouse children={mouse => (
      <p>The mouse position is {mouse.x}, {mouse.y}</p>
    )}/>
    // put it directly inside the element
    <Mouse>
      {mouse => (
        <p>The mouse position is {mouse.x}, {mouse.y}</p>
      )}
    </Mouse>
    // explicitly state that children should be a function
    // in propTypes when designing an API like this:
    // ...
    Mouse.propTypes = {
      children: PropTypes.func.isRequired
    };
    // ...

    // --- with PureComponent
    class Mouse extends React.PureComponent {
      // Same implementation as above...
    }
    class MouseTracker extends React.Component {

      // BAD, value of the "render" prop will be different on each render
      render() {
        return (
          <div>
            <h1>Move the mouse around!</h1>
            <Mouse render={mouse => (
              <Cat mouse={mouse} />
            )}/>
          </div>
        );
      }

      // OK, defined as an instance method, `this.renderTheCat` always
      // refers to *same* function when we use it in render
      renderTheCat(mouse) {
        return <Cat mouse={mouse} />;
      }
      render() {
        return (
          <div>
            <h1>Move the mouse around!</h1>
            <Mouse render={this.renderTheCat} />
          </div>
        );
      }
      // in cases where you cannot define the prop statically
      // (e.g. because you need to close over the components props and/or state)
      // Mouse should extend React.Component instead

    }
  

Hooks

useState(initialState)

    function StateRootCounter({initialCount}) {
      const [count, setCount] = React.useState(initialCount);
      // use functional updates on hooks inside event handler
      return (
        <div>
          Count: {count}
          <button onClick={() => setCount(initialCount)}>Reset</button>
          <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
          <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
        </div>
      );
    }
    const usestate_root = ReactDOM.createRoot(document.getElementById('usestate_root'));
    usestate_root.render(<StateRootCounter initialCount={101}/>);

    import React, { useState } from 'react';
    // OR use as React.useState
    function Example() {
      // declare a new state variable "count"
      const [count, setCount] = useState(0);
      // declare multiple
      const [age, setAge] = useState(42);
      const [fruit, setFruit] = useState('banana');
      // var fruitStateVariable = useState('banana'); // Returns a pair
      // var fruit = fruitStateVariable[0]; // First item in a pair
      // var setFruit = fruitStateVariable[1]; // Second item in a pair
      const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

      // if the initial state is the result of an expensive computation
      // provide a function instead, which will be executed only on the initial render
      const [state, setState] = useState(() => {
        const initialState = someExpensiveComputation(props);
        return initialState;
      });

      // useState does not automatically merge update objects
      // replicate setState method found in class components
      // by combining the function updater form with object spread syntax
      // or useReducer...
      setState(prevState => {
        return {...prevState, ...updatedValues}; // Object.assign would also work
      });

      return (
        <div>
          <p>You clicked {count} times</p>
          <button onClick={() => setCount(count + 1)}>
            Click me
          </button>
        </div>
      );

    }

    // --- --- ---
    // --- equivalent class example
    class Example extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          count: 0
        };
      }
      render() {
        return (
          <div>
            <p>You clicked {this.state.count} times</p>
            <button onClick={() => this.setState({ count: this.state.count + 1 })}>
              Click me
            </button>
          </div>
        );
      }
    }
    // --- --- ---

    // --- avoid re-creating the ignored initial state, we can pass a function
    function Table(props) {
      const [rows, setRows] = useState(() => createRows(props.count));
      // ...
    }

    // --- store many state variables
    function Box() {
      const [state, setState] = useState(
        { left: 0, top: 0, width: 100, height: 100 }
      );
      // OR
      const [position, setPosition] = useState({ left: 0, top: 0 });
      const [size, setSize] = useState({ width: 100, height: 100 });
      // ...
    }
    // ...
      useEffect(() => {
        function handleWindowMouseMove(e) {
          // Spreading "...state" ensures we don't "lose" width and height
          setState(state => ({ ...state, left: e.pageX, top: e.pageY }));
          // OR
          setPosition({ left: e.pageX, top: e.pageY });
        }
        function useWindowPosition() {
          const [position, setPosition] = useState({ left: 0, top: 0 });
          useEffect(() => {
            // ...
          }, []);
          return position;
        }
        // Note: this implementation is a bit simplified
        window.addEventListener('mousemove', handleWindowMouseMove);
        return () => window.removeEventListener('mousemove', handleWindowMouseMove);
      }, []);
    // ...

    // --- implement getDerivedStateFromProps
    // update the state right during rendering
    // re-run the component with updated state immediately
    // after exiting the first render so it wouldnt be expensive
    function ScrollView({row}) {
      let [isScrollingDown, setIsScrollingDown] = useState(false);
      // store the previous value of the row prop in a state variable so that we can compare
      let [prevRow, setPrevRow] = useState(null);
      if (row !== prevRow) {
        // Row changed since last render. Update isScrollingDown.
        setIsScrollingDown(prevRow !== null && row > prevRow);
        setPrevRow(row);
      }
      return `Scrolling down: ${isScrollingDown}`;
    }

    // --- implement forceUpdate, avoid this pattern if possible
    // ...
      const [ignored, forceUpdate] = useReducer(x => x + 1, 0);
      function handleClick() {
        forceUpdate();
      }
    // ...

    // --- manage component local state with a reducer
    function useReducer(reducer, initialState) {
      const [state, setState] = useState(initialState);
      function dispatch(action) {
        const nextState = reducer(state, action);
        setState(nextState);
      }
      return [state, dispatch];
    }
    // ...
    function Todos() {
      const [todos, dispatch] = useReducer(todosReducer, []);
      function handleAddClick(text) {
        dispatch({ type: 'add', text });
      }
      // ...
    }
  
useEffect(didUpdate)

    // not "when does this effect run"
    // "with which state does this effect synchronize with":
    useEffect(fn) // all state
    useEffect(fn, []) // no state
    useEffect(fn, [these, states])

    import React, { useEffect } from 'react';
    function Example() {
      const [count, setCount] = useState(0);
      const [isOnline, setIsOnline] = useState(null);

      // similar to componentDidMount and componentDidUpdate:
      useEffect(() => {
        document.title = `${count} clicks`; // using browser API
      });
      // only re-run the effect if count changes or any other dependency
      // }, [count]);
      // effect doesnt depend on any values from props or state,
      // so it never needs to re-run, and it should not depend
      // }, []);

      // useEffect hook with clean up, as a multiple hooks scenario
      useEffect(() => {
        function handleStatusChange(status) {
          setIsOnline(status.isOnline);
        }
        ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
        // unsubscribe from ChatAPI when the component unmounts
        // as well as before re-running the effect due to a subsequent render
        // avoid resubscribing for ids
        return () => {
          ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
        };
      });
      // }, [props.friend.id]); // subscription is recreated only if props.friend.id changes

      useEffect(() => {
        const id = setInterval(() => {
          setCount(c => c + 1); // doesnt depend on "count" variable outside
        }, 1000);
        return () => clearInterval(id);
      }, []); // doesnt use any variables in the component scope

      useEffect(function persistForm() {
        // rules are not breaking this way, condition is inside hook
        if (name !== '') {
          localStorage.setItem('formData', name);
        }
      });

      const onlineStatus = isOnline ? 'Online' : 'Offline';

      return (
        <div>
          <p>You are {onlineStatus} and clicked {count} times</p>
          <button onClick={() => setCount(count + 1)}>
            Click me
          </button>
        </div>
      );
    }

    // --- class analogue
    class Example extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          count: 0,
          isOnline: null
        };
        this.handleStatusChange = this.handleStatusChange.bind(this);
      }

      // duplicates code in lifecycle methods !
      componentDidMount() {
        document.title = `You clicked ${this.state.count} times`;
        ChatAPI.subscribeToFriendStatus(
          this.props.friend.id,
          this.handleStatusChange
        );
      }
      componentDidUpdate() {

        document.title = `You clicked ${this.state.count} times`;
        // extra comparison to avoid performance problem
        // on cleaning up or applying the effect after every render
        if (prevState.count !== this.state.count) {
          document.title = `You clicked ${this.state.count} times`;
        }

        // if the friend prop changes while the component is on the screen
        // our component would continue displaying the online status of a different friend
        // Unsubscribe from the previous friend.id
        ChatAPI.unsubscribeFromFriendStatus(
          prevProps.friend.id,
          this.handleStatusChange
        );
        // Subscribe to the next friend.id
        ChatAPI.subscribeToFriendStatus(
          this.props.friend.id,
          this.handleStatusChange
        );

      }
      componentWillUnmount() {
        ChatAPI.unsubscribeFromFriendStatus(
          this.props.friend.id,
          this.handleStatusChange
        );
      }

      handleStatusChange(status) {
        this.setState({
          isOnline: status.isOnline
        });
      }

      const onlineStatus = isOnline ? 'Online' : 'Offline';

      render() {
        return (
          <div>
            <p>You are {onlineStatus} and clicked {count} times</p>
            <button onClick={() => this.setState({ count: this.state.count + 1 })}>
              Click me
            </button>
          </div>
        );
      }
    }

    // --- dependency, function inside effect
    function ProductPage({ productId }) {
      const [product, setProduct] = useState(null);
      useEffect(() => {
        let ignore = false; // handle out-of-order responses
        async function fetchProduct() {
          const response = await fetch('http://myapi/product' + productId);
          const json = await response.json();
          if (!ignore) setProduct(json);
        }
        return () => { ignore = true };
      }, [productId]); // valid because our effect only uses productId
      // ...
    }
    // --- wrapped dependency
    // change in the productId prop of ProductPage
    // automatically triggers a refetch in the ProductDetails component
    function ProductPage({ productId }) {
      // wrap with useCallback to avoid change on every render
      const fetchProduct = useCallback(() => {
        // ... Does something with productId ...
      }, [productId]); // all useCallback dependencies are specified
      return <ProductDetails fetchProduct={fetchProduct} />;
    }
    function ProductDetails({ fetchProduct }) {
      useEffect(() => {
        fetchProduct();
      }, [fetchProduct]); // all useEffect dependencies are specified
      // ...
    }
  
useContext(MyContext)

    const themes = {
      light: {
        foreground: "#000000",
        background: "#eeeeee"
      },
      dark: {
        foreground: "#ffffff",
        background: "#222222"
      }
    };
    const ThemeContext = React.createContext(themes.light);
    function App() {
      return (
        <ThemeContext.Provider value={themes.dark}>
          <Toolbar />
        </ThemeContext.Provider>
      );
    }
    function Toolbar(props) {
      return (
        <div>
          <ThemedButton />
        </div>
      );
    }
    function ThemedButton() {
      const theme = useContext(ThemeContext);
      return (
        <button style={{ background: theme.background, color: theme.foreground }}>
          I am styled by theme context!
        </button>
      );
    }
  
custom hooks

    // extracts logic from previous examples
    import React, { useState, useEffect } from 'react';
    function useFriendStatus(friendID) {
      const [isOnline, setIsOnline] = useState(null);
      function handleStatusChange(status) {
        setIsOnline(status.isOnline);
      }
      useEffect(() => {
        ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
        return () => {
          ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
        };
      });
      return isOnline;
    }
    // and reuse it
    function FriendStatus(props) {
      const isOnline = useFriendStatus(props.friend.id);
      if (isOnline === null) { return 'Loading...'; }
      return isOnline ? 'Online' : 'Offline';
    }
    function FriendListItem(props) {
      const isOnline = useFriendStatus(props.friend.id);
      return (
        <li style={{ color: isOnline ? 'green' : 'black' }}>
          {props.friend.name}
        </li>
      );
    }

    // --- pass information between hooks
    const friendList = [
      { id: 1, name: 'Phoebe' },
      { id: 2, name: 'Rachel' },
      { id: 3, name: 'Ross' },
    ];
    function ChatRecipientPicker() {
      // recipientID updates resubscribes status
      const [recipientID, setRecipientID] = useState(1);
      const isRecipientOnline = useFriendStatus(recipientID);
      return (
        <>
          <Circle color={isRecipientOnline ? 'green' : 'red'} />
          <select
            value={recipientID}
            onChange={e => setRecipientID(Number(e.target.value))}
          >
            {friendList.map(friend => (
              <option key={friend.id} value={friend.id}>
                {friend.name}
              </option>
            ))}
          </select>
        </>
      );
    }
  
lint plugin

    npm install eslint-plugin-react-hooks --save-dev
    //ESLint configuration
    {
      "plugins": [
        // ...
        "react-hooks"
      ],
      "rules": {
        // ...
        "react-hooks/rules-of-hooks": "error", // Checks rules of Hooks
        "react-hooks/exhaustive-deps": "warn" // Checks effect dependencies
      }
    }
  

additional hooks - specific edge cases, variants of the basic ones

useReducer(reducer, initialArg, init)

    // --- INITAL STATE
    const initialReducerCounter = {count: 0};
    function reducerForCounter(state, action) {
      switch (action.type) {
        case 'increment':
          return {count: state.count + 1};
        case 'decrement':
          return {count: state.count - 1};
        default:
          throw new Error();
      }
    }
    function UseReducerCounter({initialState}) {
      const [state, dispatch] = React.useReducer(
        reducerForCounter,
        initialState
      );
      return (
        <div>
          Count: {state.count}
          <button onClick={() => dispatch({type: 'increment'})}>+</button>
          <button onClick={() => dispatch({type: 'decrement'})}>-</button>
        </div>
      );
    }
    // const usereducer_root = ReactDOM.createRoot(document.getElementById("usereducer_root"));
    // usereducer_root.render(<UseReducerCounter initialState={initialReducerCounter}/>);

    // --- LAZY INIT
    function initLazyCounter(initialCount) {
      return {count: initialCount};
    }
    function reducerForLazyCounter(state, action) {
      switch (action.type) {
        case 'increment':
          return {count: state.count + 1};
        case 'decrement':
          return {count: state.count - 1};
        case 'reset':
          return initLazyCounter(action.payload);
        default:
          throw new Error();
      }
    }
    function UseReducerLazyCounter({initialState}) {
      const [state, dispatch] = React.useReducer(
        reducerForLazyCounter,
        initialState,
        initLazyCounter
      );
      return (
        <div>
          Count: {state.count}
          <button
            onClick={() => dispatch({type: 'reset', payload: initialState})}>
            Reset
          </button>
          <button onClick={() => dispatch({type: 'increment'})}>+</button>
          <button onClick={() => dispatch({type: 'decrement'})}>-</button>
        </div>
      );
    }
    const usereducer_root = ReactDOM.createRoot(document.getElementById("usereducer_root"));
    usereducer_root.render(<UseReducerLazyCounter initialState={0}/>);

    // --- deep update, passing callbacks through every level of a component tree
    const TodosDispatch = React.createContext(null);
    function TodosApp() {
      // "dispatch" wont change between re-renders
      const [todos, dispatch] = useReducer(todosReducer);
      return (
        <TodosDispatch.Provider value={dispatch}>
          <DeepTree todos={todos} />
        </TodosDispatch.Provider>
      );
    }
    function DeepChild(props) {
      // if we want to perform an action, we can get dispatch from context
      // pass actions up to TodosApp
      const dispatch = useContext(TodosDispatch);
      function handleClick() {
        dispatch({ type: 'add', text: 'hello' });
      }
      return (
        <button onClick={handleClick}>Add todo</button>
      );
    }
  
useCallback(fn, deps)

    const memoizedCallback = useCallback(
      () => {
        doSomething(a, b);
      },
      [a, b],
    );

    // --- measure the position or size of a DOM node
    function MeasureExample() {
      const [rect, ref] = useClientRect();
      return (
        <>
          <h1 ref={ref}>Hello, world</h1>
          {rect !== null &&
            <h2>The above header is {Math.round(rect.height)}px tall</h2>
          }
        </>
      );
    }
    function useClientRect() {
      const [rect, setRect] = useState(null);
      const ref = useCallback(node => {
        if (node !== null) {
          setRect(node.getBoundingClientRect());
        }
      }, []); // callback doesnt change between the re-renders, dont call it unnecessarily
      return [rect, ref];
    }

    // --- read an often-changing value from useCallback
    // function is an event handler and isnt used during rendering
    // using ref as an instance variable, saving the last committed value into it manually
    function Form() {
      const [text, updateText] = useState('');
      const textRef = useRef();
      useEffect(() => {
        textRef.current = text; // write it to the ref
      });
      const handleSubmit = useCallback(() => {
        const currentText = textRef.current; // Read it from the ref
        alert(currentText);
      }, [textRef]); // dont recreate handleSubmit like [text] would do
      return (
        <>
          <input value={text} onChange={e => updateText(e.target.value)} />
          <ExpensiveTree onSubmit={handleSubmit} />
        </>
      );
    }
    // extract to custom hook
    function Form() {
      const [text, updateText] = useState('');
      // will be memoized even if `text` changes:
      const handleSubmit = useEventCallback(() => {
        alert(text);
      }, [text]);
      return (
        <>
          <input value={text} onChange={e => updateText(e.target.value)} />
          <ExpensiveTree onSubmit={handleSubmit} />
        </>
      );
    }
    function useEventCallback(fn, dependencies) {
      const ref = useRef(() => {
        throw new Error('Cannot call an event handler while rendering');
      });
      useEffect(() => {
        ref.current = fn;
      }, [fn, ...dependencies]);
      return useCallback(() => {
        const fn = ref.current;
        return fn();
      }, [ref]);
    }
  
useMemo(() => fn, deps)

    const memoizedValue = useMemo(
      () => computeExpensiveValue(a, b),
      [a, b]
    );

    const Button = React.memo((props) => {
      // component
    });

    // skip an expensive re-render of a child
    function Parent({ a, b }) {
      // Only re-rendered if "a" changes:
      const child1 = useMemo(() => <Child1 a={a} />, [a]);
      // Only re-rendered if "b" changes:
      const child2 = useMemo(() => <Child2 b={b} />, [b]);
      return (
        <>
          {child1}
          {child2}
        </>
      )
    }

    // avoid unnecessary re-renders
    const CountButton = React.memo(function CountButton({onClick, count}) {
      return <button onClick={onClick}>{count}</button>;
    })
    function DualCounter() {
      const [count1, setCount1] = React.useState(0);
      const increment1 = React.useCallback(() => setCount1(c => c + 1), []);
      const [count2, setCount2] = React.useState(0);
      const increment2 = React.useCallback(() => setCount2(c => c + 1), []);
      return (
        <>
          <CountButton count={count1} onClick={increment1} />
          <CountButton count={count2} onClick={increment2} />
        </>
      )
    }
  
useRef(initialValue)

    function UseRefExamples() {
      const [count, setCount] = React.useState(0);
      const prevCount = useRefUsePrevious(count); // store any other calculated value
      const inputEl = React.useRef(null);
      const onButtonClick = () => {
        // "current" points to the mounted text input element
        inputEl.current.focus();
      };
      return (
        <div>
          <input ref={inputEl} type="text" /><br/>
          <button onClick={onButtonClick}>Focus the input</button>
          <div>Now: {count}, before: {prevCount}</div>
          <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
          <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
        </div>
      );
    }
    function useRefUsePrevious(value) {
      const ref = React.useRef();
      React.useEffect(() => {
        ref.current = value;
      });
      return ref.current;
    }
    const useref_root = ReactDOM.createRoot(document.getElementById("useref_root"));
    useref_root.render(<UseRefExamples/>);

    // --- avoid re-creating the useRef() initial value
    function Image(props) {
      const ref = useRef(null);
      // IntersectionObserver is created lazily once
      function getObserver() {
        if (ref.current === null) {
          ref.current = new IntersectionObserver(onIntersect);
        }
        return ref.current;
      }
      //call getObserver()
      // ...
    }

    // like instance variables
    // ...
    function Timer() {
      const intervalRef = useRef();
      useEffect(() => {
        const id = setInterval(() => {
          // ...
        });
        intervalRef.current = id;
        return () => {
          clearInterval(intervalRef.current);
        };
      });
      // ...
      function handleCancelClick() {
        clearInterval(intervalRef.current);
      }
      // ...
    }
  
useImperativeHandle(ref, createHandle, [deps])

    // parent component that renders <FancyInput ref={fancyInputRef} />
    // would be able to call fancyInputRef.current.focus()
    function FancyInput(props, ref) {
      const inputRef = useRef();
      useImperativeHandle(ref, () => ({
        focus: () => {
          inputRef.current.focus();
        }
      }));
      return <input ref={inputRef} ... />;
    }
    FancyInput = forwardRef(FancyInput);
  
useLayoutEffect(didUpdateFn)
useDebugValue(value[,formattingFn])

    function useFriendStatus(friendID) {
      const [isOnline, setIsOnline] = useState(null);
      // ...
      // show a label in DevTools next to this Hook
      // e.g. "FriendStatus: Online"
      useDebugValue(isOnline ? 'Online' : 'Offline');
      return isOnline;
    }

    // --- with formattingFn:
    useDebugValue(date, date => date.toDateString());
  
useDeferredValue(value)

    // memoizing deferred children
    // if you want to prevent a child component from re-rendering during an urgent update,
    // also memoize that component with React.memo or React.useMemo
    function Typeahead() {
      const query = useSearchQuery('');
      const deferredQuery = useDeferredValue(query);
      // Memoizing tells React to only re-render when deferredQuery changes,
      // not when query changes.
      const suggestions = useMemo(() =>
        <SearchSuggestions query={deferredQuery} />,
        [deferredQuery]
      );
      return (
        <>
          <SearchInput query={query} />
          <Suspense fallback="Loading results...">
            {suggestions}
          </Suspense>
        </>
      );
    }
    // re-render them when deferredQuery changes and not when query changes
  
useTransition()

    function App() {
      const [isPending, startTransition] = useTransition();
      const [count, setCount] = useState(0);
      function handleClick() {
        startTransition(() => {
          setCount(c => c + 1);
        })
      }
      return (
        <div>
          {isPending && <Spinner />}
          <button onClick={handleClick}>{count}</button>
        </div>
      );
    }
  
useId()

    function Checkbox() {
      const id = useId();
      return (
        <>
          <label htmlFor={id}>Do you like React?</label>
          <input id={id} type="checkbox" name="react"/>
        </>
      );
    };
    // for multiple IDs in the same component, append a suffix using the same id
    function NameFields() {
      const id = useId();
      return (
        <div>
          <label htmlFor={id + '-firstName'}>First Name</label>
          <div>
            <input id={id + '-firstName'} type="text" />
          </div>
          <label htmlFor={id + '-lastName'}>Last Name</label>
          <div>
            <input id={id + '-lastName'} type="text" />
          </div>
        </div>
      );
    }
  

Hooks provided for library authors

useSyncExternalStore(subscribe, getSnapshot[, getServerSnapshot])

    // subscribes to the entire store:
    const state = useSyncExternalStore(store.subscribe, store.getSnapshot);
    // subscribe to a specific field:
    const selectedField = useSyncExternalStore(
      store.subscribe,
      () => store.getSnapshot().selectedField,
    );
    // when server rendering, serialize the store value used on the server,
    // and provide it to useSyncExternalStore
    // React will use this snapshot during hydration to prevent server mismatches:
    const selectedField = useSyncExternalStore(
      store.subscribe,
      () => store.getSnapshot().selectedField,
      () => INITIAL_SERVER_SNAPSHOT.selectedField,
    );
  
useInsertionEffect(didUpdate)

AJAX


    class AjaxFetchExample extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          error: null,
          isLoaded: false,
          items: []
        };
      }
      componentDidMount() {
        fetch("php/ajax_json.php")
          .then(res => res.json())
          .then(
            (result) => {
              this.setState({
                isLoaded: true,
                items: result.items.response
              });
            },
            // instead of a catch() block so that we dont swallow
            // exceptions from actual bugs in components
            (error) => {
              this.setState({
                isLoaded: true,
                error
              });
            }
          )
      }
      render() {
        const { error, isLoaded, items } = this.state;
        if (error) {
          return <div>Error: {error.message}</div>;
        } else if (!isLoaded) {
          return <div>Loading...</div>;
        } else {
          return (
            <ul>
              {items.map(item => (
                <li key={item.name}>
                  {item.name} {item.price}
                </li>
              ))}
            </ul>
          );
        }
      }
    }
    const ajax_root = ReactDOM.createRoot(document.getElementById("ajax_root"));
    ajax_root.render(<AjaxFetchExample/>);
  

Back to Main Page