Type Checking

PropTypes


    import PropTypes from 'prop-types';

    class Greeting extends React.Component {
      render() {
        return (
          <h1>Hello, {this.props.name}</h1>
        );
      }
    }
    Greeting.propTypes = {
      name: PropTypes.string
    };

    // --- only a single child can be passed to a component as children
    class MyComponent extends React.Component {
      render() {
        // This must be exactly one element or it will warn.
        const children = this.props.children;
        return (
          <div>
            {children}
          </div>
        );
      }
    }
    MyComponent.propTypes = {
      children: PropTypes.element.isRequired
    };

    // --- default values for props
    class Greeting extends React.Component {
      render() {
        return (
          <h1>Hello, {this.props.name}</h1>
        );
      }
    }
    // Specifies the default values for props:
    Greeting.defaultProps = {
      name: 'Stranger'
    };

    // --- different validators provided
    MyComponent.propTypes = {
      // declare that a prop is a specific JS type
      // by default, these are all optional
      optionalArray: PropTypes.array,
      optionalBool: PropTypes.bool,
      optionalFunc: PropTypes.func,
      optionalNumber: PropTypes.number,
      optionalObject: PropTypes.object,
      optionalString: PropTypes.string,
      optionalSymbol: PropTypes.symbol,
      // anything that can be rendered: numbers, strings,
      // elements or an array (or fragment) containing these types
      optionalNode: PropTypes.node,
      // React element
      optionalElement: PropTypes.element,
      // prop is an instance of a class, this uses JS instanceof operator
      optionalMessage: PropTypes.instanceOf(Message),
      // ensure that prop is limited to specific values
      // by treating it as an enum
      optionalEnum: PropTypes.oneOf(['News', 'Photos']),
      // one of many types
      optionalUnion: PropTypes.oneOfType([
        PropTypes.string,
        PropTypes.number,
        PropTypes.instanceOf(Message)
      ]),
      // array of a certain type
      optionalArrayOf: PropTypes.arrayOf(PropTypes.number),
      // object with property values of a certain type
      optionalObjectOf: PropTypes.objectOf(PropTypes.number),
      // object taking on a particular shape
      optionalObjectWithShape: PropTypes.shape({
        color: PropTypes.string,
        fontSize: PropTypes.number
      }),
      // chain any of the above with "isRequired" to make sure a warning
      // is shown if the prop isnt provided
      requiredFunc: PropTypes.func.isRequired,
      // value of any data type
      requiredAny: PropTypes.any.isRequired,
      // specify a custom validator
      // returns an Error object if the validation fails
      // dont "console.warn" or throw, as this wont work inside "oneOfType"
      customProp: function(props, propName, componentName) {
        if (!/matchme/.test(props[propName])) {
          return new Error(
            'Invalid prop `' + propName + '` supplied to' +
            ' `' + componentName + '`. Validation failed.'
          );
        }
      },
      // supply a custom validator to "arrayOf" and "objectOf"
      // should return an Error object if the validation fails
      // will be called for each key in the array or object
      // first two arguments of the validator are the array or object itself
      // and the current item key
      customArrayProp: PropTypes.arrayOf(
        function(propValue, key, componentName, location, propFullName
      ) {
        if (!/matchme/.test(propValue[key])) {
          return new Error(
            'Invalid prop `' + propFullName + '` supplied to' +
            ' `' + componentName + '`. Validation failed.'
          );
        }
      })
    };

    // --- Babel transform (like transform-class-properties)
    // declare defaultProps as static property within a React component class
    // syntax has not yet been finalized though and will require a compilation step
    class Greeting extends React.Component {
      static defaultProps = {
        name: 'stranger'
      }
      render() {
        return (
          <div>Hello, {this.props.name}</div>
        )
      }
    }
  

Strict Mode


    import React from 'react';
    function ExampleApplication() {
      return (
        <div>
          <Header />
          <React.StrictMode>
            <div>
              <ComponentOne />
              <ComponentTwo />
            </div>
          </React.StrictMode>
          <Footer />
        </div>
      );
    }
  

Lazy/Suspense


    // --- React.lazy
    // define a component that is loaded dynamically that arent used during the initial render
    const OtherComponent = React.lazy(() => import('./OtherComponent'));
    function MyComponent() {
      return (
        <div>
          <OtherComponent />
        </div>
      );
    }

    // --- React.Suspense
    // show some fallback content while we are waiting for it to load
    // "fallback" prop accepts any React elements that you want to render
    // while waiting for the component to load
    // place Suspense where you want to see a loading indicator,
    // but to use lazy() wherever you want to do code splittin
    const OtherComponent = React.lazy(() => import('./OtherComponent'));
    const AnotherComponent = React.lazy(() => import('./AnotherComponent'));
    function MyComponent() {
      return (
        <div>
          <Suspense fallback={<div>Loading...</div>}>
            <section>
              <OtherComponent />
              <AnotherComponent />
            </section>
          </Suspense>
        </div>
      );
    }

    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
    import React, { Suspense, lazy } from 'react';
    const Home = lazy(() => import('./routes/Home'));
    const About = lazy(() => import('./routes/About'));
    const App = () => (
      <Router>
        <Suspense fallback={<div>Loading...</div>}>
          <Switch>
            <Route exact path="/" component={Home}/>
            <Route path="/about" component={About}/>
          </Switch>
        </Suspense>
      </Router>
    );

    // create an intermediate module that reexports it as the default
    // treeshaking keeps working and that you dont pull in unused components
    // ManyComponents.js
    export const MyComponent = /* ... */;
    export const MyUnusedComponent = /* ... */;
    // MyComponent.js
    export { MyComponent as default } from "./ManyComponents.js";
    // MyApp.js
    import React, { lazy } from 'react';
    const MyComponent = lazy(() => import("./MyComponent.js"));
  

Styling/CSS


    // --- style
    const divStyle = {
      color: 'blue',
      backgroundImage: 'url(' + imgUrl + ')',
      WebkitTransition: 'all', // note the capital 'W' here
      msTransition: 'all' // 'ms' is the only lowercase vendor prefix
    };
    function HelloWorldComponent() {
      return <div style={divStyle}>Hello World!</div>;
    }
    // Result style: '10px'
    <div style={{ height: 10 }}>
      Hello World!
    </div>
    // Result style: '10%'
    <div style={{ height: '10%' }}>
      Hello World!
    </div>

    // --- classes depends on the component props or state
    // ...
      render() {
        let className = 'menu';
        if (this.props.isActive) {
          className += ' menu-active';
        }
        return <span className={className}>Menu</span>
      }
    // ...
  

without ES6/JSX


    // define a React component as a plain JavaScript class
    class Greeting extends React.Component {
      render() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    }
    // without ES6 , you may use the create-react-class module instead:
    var createReactClass = require('create-react-class');
    var Greeting = createReactClass({
      render: function() {
        return <h1>Hello, {this.props.name}</h1>;
      }
    });

    // --- declaring default props
    // with functions and ES6 classes defaultProps is defined as a property
    class Greeting extends React.Component {
      // ...
    }
    Greeting.defaultProps = {
      name: 'Mary'
    };
    // createReactClass(), define getDefaultProps() as a function on the passed object:
    var Greeting = createReactClass({
      getDefaultProps: function() {
        return {
          name: 'Mary'
        };
      },
      // ...
    });

    // --- setting the initial state
    // in ES6 classes define the initial state by assigning this.state in the constructor:
    class Counter extends React.Component {
      constructor(props) {
        super(props);
        this.state = {count: props.initialCount};
      }
      // ...
    }
    // with createReactClass() provide a separate getInitialState
    // that returns the initial state:
    var Counter = createReactClass({
      getInitialState: function() {
        return {count: this.props.initialCount};
      },
      // ...
    });

    // --- autobinding
    // in ES6 use .bind(this) in the constructor:
    class SayHello extends React.Component {
      constructor(props) {
        super(props);
        this.state = {message: 'Hello!'};
        // This line is important!
        this.handleClick = this.handleClick.bind(this);
      }
      handleClick() {
        alert(this.state.message);
      }
      render() {
        // Because `this.handleClick` is bound, we can use it as an event handler.
        return (
          <button onClick={this.handleClick}>
            Say hello
          </button>
        );
      }
    }
    // with createReactClass(), not necessary because it binds all methods:
    var SayHello = createReactClass({
      getInitialState: function() {
        return {message: 'Hello!'};
      },
      handleClick: function() {
        alert(this.state.message);
      },
      render: function() {
        return (
          <button onClick={this.handleClick}>
            Say hello
          </button>
        );
      }
    });
    // or enable the experimental Class Properties syntax proposal with Babel:
    class SayHello extends React.Component {
      constructor(props) {
        super(props);
        this.state = {message: 'Hello!'};
      }
      // WARNING: this syntax is experimental!
      // Using an arrow here binds the method:
      handleClick = () => {
        alert(this.state.message);
      }
      render() {
        return (
          <button onClick={this.handleClick}>
            Say hello
          </button>
        );
      }
    }

    // --- experimental mixins !!!
    // when very different components may share some common functionality
    // one common use case is a component wanting to update itself on a time interval
    var SetIntervalMixin = {
      componentWillMount: function() {
        this.intervals = [];
      },
      setInterval: function() {
        this.intervals.push(setInterval.apply(null, arguments));
      },
      componentWillUnmount: function() {
        this.intervals.forEach(clearInterval);
      }
    };
    var createReactClass = require('create-react-class');
    var TickTock = createReactClass({
      mixins: [SetIntervalMixin], // Use the mixin
      getInitialState: function() {
        return {seconds: 0};
      },
      componentDidMount: function() {
        this.setInterval(this.tick, 1000); // Call a method on the mixin
      },
      tick: function() {
        this.setState({seconds: this.state.seconds + 1});
      },
      render: function() {
        return (
          <p>
            React has been running for {this.state.seconds} seconds.
          </p>
        );
      }
    });
    const rootElement = document.getElementById('example');
    const root = createRoot(rootElement);
    root.render(
      <TickTock />
    );
    // if a component is using multiple mixins
    // and several mixins define the same lifecycle method
    // (i.e. several mixins want to do some cleanup when the component is destroyed),
    // all of the lifecycle methods are guaranteed to be called
    // methods run in the order mixins were listed, followed by a method call on the component
  

ReactDOMClient


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

    const root = createRoot(container);
    root.render(element);
    // ...
    root.unmount();
  

ReactDOMClient


    // ES modules
    import * as ReactDOMServer from 'react-dom/server';
    // CommonJS
    var ReactDOMServer = require('react-dom/server');
  

    let didError = false;
    const stream = renderToPipeableStream(
      <App />,
      {
        onShellReady() {
          // The content above all Suspense boundaries is ready.
          // If something errored before we started streaming, we set the error code appropriately.
          res.statusCode = didError ? 500 : 200;
          res.setHeader('Content-type', 'text/html');
          stream.pipe(res);
        },
        onShellError(error) {
          // Something errored before we could complete the shell so we emit an alternative shell.
          res.statusCode = 500;
          res.send(
            '<!doctype html><p>Loading...</p><script src="clientrender.js"></script>'
          );
        },
        onAllReady() {
          // If you don't want streaming, use this instead of onShellReady.
          // This will fire after the entire page content is ready.
          // You can use this for crawlers or static generation.

          // res.statusCode = didError ? 500 : 200;
          // res.setHeader('Content-type', 'text/html');
          // stream.pipe(res);
        },
        onError(err) {
          didError = true;
          console.error(err);
        },
      }
    );
  

    let controller = new AbortController();
    let didError = false;
    try {
      let stream = await renderToReadableStream(
        <html>
          <body>Success</body>
        </html>,
        {
          signal: controller.signal,
          onError(error) {
            didError = true;
            console.error(error);
          }
        }
      );
      // This is to wait for all Suspense boundaries to be ready. You can uncomment
      // this line if you want to buffer the entire HTML instead of streaming it.
      // You can use this for crawlers or static generation:
      // await stream.allReady;
      return new Response(stream, {
        status: didError ? 500 : 200,
        headers: {'Content-Type': 'text/html'},
      });
    } catch (error) {
      return new Response(
        '<!doctype html><p>Loading...</p><script src="clientrender.js"></script>',
        {
          status: 500,
          headers: {'Content-Type': 'text/html'},
        }
      );
    }
  

ReactTest

ReactTestUtils

    // --- COMPONENT
    class Counter extends React.Component {
      constructor(props) {
        super(props);
        this.state = {count: 0};
        this.handleClick = this.handleClick.bind(this);
      }
      componentDidMount() {
        document.title = `You clicked ${this.state.count} times`;
      }
      componentDidUpdate() {
        document.title = `You clicked ${this.state.count} times`;
      }
      handleClick() {
        this.setState(state => ({
          count: state.count + 1,
        }));
      }
      render() {
        return (
          <div>
            <p>You clicked {this.state.count} times</p>
            <button onClick={this.handleClick}>
              Click me
            </button>
          </div>
        );
      }
    }

    // --- HOOKS version
    function Example() {
      const [count, setCount] = useState(0);
      useEffect(() => {
        document.title = `You clicked ${count} times`;
      });
      return (
        <div>
          <p>You clicked {count} times</p>
          <button onClick={() => setCount(count + 1)}>
            Click me
          </button>
        </div>
      );
    }

    // --- TEST
    import React from 'react';
    import * as ReactDOM from 'react-dom/client';
    import { act } from 'react-dom/test-utils';
    import Counter from './Counter';
    let container;
    beforeEach(() => {
      container = document.createElement('div');
      document.body.appendChild(container);
    });
    afterEach(() => {
      document.body.removeChild(container);
      container = null;
    });
    it('can render and update a counter', () => {
      // Test first render and componentDidMount
      act(() => {
        const root = ReactDOM.createRoot(container);
        root.render((<Counter />);
      });
      const button = container.querySelector('button');
      const label = container.querySelector('p');
      expect(label.textContent).toBe('You clicked 0 times');
      expect(document.title).toBe('You clicked 0 times');
      // Test second render and componentDidUpdate
      act(() => {
        button.dispatchEvent(new MouseEvent('click', {bubbles: true}));
      });
      expect(label.textContent).toBe('You clicked 1 times');
      expect(document.title).toBe('You clicked 1 times');
      // asynchronous version of act, to apply resolved promises
      await act(async () => {
        render(<User id="123" />, container);
      });
    });

    // --- clicking an element
    // <button ref={(node) => this.button = node}>...</button>
    const node = this.button;
    ReactTestUtils.Simulate.click(node);

    // --- changing the value of an input field and then pressing ENTER
    // <input ref={(node) => this.textInput = node} />
    const node = this.textInput;
    node.value = 'giraffe';
    ReactTestUtils.Simulate.change(node);
    ReactTestUtils.Simulate.keyDown(node, {key: "Enter", keyCode: 13, which: 13});
  
ShallowRenderer

    // --- COMPONENT
    function MyComponent() {
      return (
        <div>
          <span className="heading">Title</span>
          <Subcomponent foo="bar" />
        </div>
      );
    }

    // --- ASSERT
    import ShallowRenderer from 'react-test-renderer/shallow';
    // in test:
    const renderer = new ShallowRenderer();
    renderer.render(<MyComponent />);
    const result = renderer.getRenderOutput();
    expect(result.type).toBe('div');
    expect(result.props.children).toEqual([
      <span className="heading">Title</span>,
      <Subcomponent foo="bar" />
    ]);
  
TestRenderer

    // --- grab a snapshot
    import TestRenderer from 'react-test-renderer';
    function Link(props) {
      return <a href={props.page}>{props.children}</a>;
    }
    const testRenderer = TestRenderer.create(
      <Link page="https://www.facebook.com/">Facebook</Link>
    );
    console.log(testRenderer.toJSON());
    // { type: 'a',
    //   props: { href: 'https://www.facebook.com/' },
    //   children: [ 'Facebook' ] }

    // --- traverse the output to find specific nodes and make assertions about them
    import TestRenderer from 'react-test-renderer';
    function MyComponent() {
      return (
        <div>
          <SubComponent foo="bar" />
          <p className="my">Hello</p>
        </div>
      )
    }
    function SubComponent() {
      return (
        <p className="sub">Sub</p>
      );
    }
    const testRenderer = TestRenderer.create(<MyComponent />);
    const testInstance = testRenderer.root;
    expect(testInstance.findByType(SubComponent).props.foo).toBe('bar');
    expect(testInstance.findByProps({className: "sub"}).children).toEqual(['Sub']);

    // ---
    import TestRenderer from 'react-test-renderer';
    class MyComponent extends React.Component {
      constructor(props) {
        super(props);
        this.input = null;
      }
      componentDidMount() {
        this.input.focus();
      }
      render() {
        return <input type="text" ref={el => this.input = el} />
      }
    }
    let focused = false;
    TestRenderer.create(
      <MyComponent />,
      {
        createNodeMock: (element) => {
          if (element.type === 'input') {
            // mock a focus function
            return {
              focus: () => {
                focused = true;
              }
            };
          }
          return null;
        }
      }
    );
    expect(focused).toBe(true);
  

Project Structure

by features or routes


    common/
      Avatar.js
      Avatar.css
      APIUtils.js
      APIUtils.test.js
    feed/
      index.js
      Feed.js
      Feed.css
      FeedStory.js
      FeedStory.test.js
      FeedAPI.js
    profile/
      index.js
      Profile.js
      ProfileHeader.js
      ProfileHeader.css
      ProfileAPI.js
  

by file type


    api/
      APIUtils.js
      APIUtils.test.js
      ProfileAPI.js
      UserAPI.js
    components/
      Avatar.js
      Avatar.css
      Feed.js
      Feed.css
      FeedStory.js
      FeedStory.test.js
      Profile.js
      ProfileHeader.js
      ProfileHeader.css
  

TOOLS

create-react-app 4.0.3

styles and assets


    // --- Webpack custom way of "extending" the concept of import beyond JS
    // express that a JS file depends on a CSS file, import the CSS from the JS file
    // not required for React !
    // makes code less portable to other build tools and environments than Webpack
    // - Button.css
    .Button {
      padding: 20px;
    }
    // - Button.js
    import React, { Component } from 'react';
    import './Button.css'; // Tell Webpack that Button.js uses these styles
    class Button extends Component {
      render() {
        // You can use them as regular CSS styles
        return <div className="Button" />;
      }
    }

    // --- "CSS Modules" Stylesheet
    // let you use the same CSS class name in different files without worrying about naming clashes.
    // alongside regular stylesheets using the [name].module.css file naming convention.
    // modules allows the scoping of CSS by automatically,
    // creating a unique classname of the format [filename]\_[classname]\_\_[hash]
    // - Button.module.css
    .error {
      background-color: red;
    }
    // - another-stylesheet.css
    .error {
      color: red;
    // - Button.js
    import React, { Component } from 'react';
    import styles from './Button.module.css'; // Import css modules stylesheet as styles
    import './another-stylesheet.css'; // Import regular stylesheet
    class Button extends Component {
      render() {
        // reference as a js object
        return <button className={styles.error}>Error Button</button>;
      }
    }

    // --- importing images that are less than 10,000 bytes returns a data URI
    // instead of a path
    // applies to the following file extensions: bmp, gif, jpg, jpeg, png
    import React from 'react';
    import logo from './logo.png'; // Tell Webpack this JS file uses this image
    console.log(logo); // /logo.84287d09.png
    function Header() {
      // Import result is the URL of image
      return <img src={logo} alt="Logo" />;
    }
    export default Header;
    // - for css:
    .Logo {
      background-image: url(./logo.png);
    }

    // --- import SVGs directly as React components
    // curly braces in the import
    // tells CRA about React component that renders an SVG, rather than its filename
    import { ReactComponent as Logo } from './logo.svg';
    const App = () => (
      <div>
        {/* Logo is an actual React component */}
        <Logo />
      </div>
    );

    // --- code splitting, module exports
    // this will make moduleA.js and all its unique dependencies as a separate chunk
    // that only loads after the user clicks the 'Load' button
    // use it with async / await syntax if you prefer it
    // - moduleA.js
    const moduleA = 'Hello';
    export { moduleA };
    // - App.js
    import React, { Component } from 'react';
    class App extends Component {
      handleClick = () => {
        import('./moduleA')
          .then(({ moduleA }) => {
            // Use moduleA
          })
          .catch(err => {
            // Handle failure
          });
      };
      render() {
        return (
          <div>
            <button onClick={this.handleClick}>Load</button>
          </div>
        );
      }
    }
    export default App;
  

adjust various dev/prod settings with environment variables in shell or within .env file

Variable Development Production Usage
BROWSER ✅ Used 🚫 Ignored By default, Create React App will open the default system browser, favoring Chrome on macOS. Specify a browser to override this behavior, or set it to none to disable it completely. If you need to customize the way the browser is launched, you can specify a node script instead. Any arguments passed to npm start will also be passed to this script, and the url where your app is served will be the last argument. Your script's file name must have the .js extension.
BROWSER_ARGS ✅ Used 🚫 Ignored When the BROWSER environment variable is specified, any arguments that you set to this environment variable will be passed to the browser instance. Multiple arguments are supported as a space separated list. By default, no arguments are passed through to browsers.
HOST ✅ Used 🚫 Ignored By default, the development web server binds to all hostnames on the device (localhost, LAN network address, etc.). You may use this variable to specify a different host.
PORT ✅ Used 🚫 Ignored By default, the development web server will attempt to listen on port 3000 or prompt you to attempt the next available port. You may use this variable to specify a different port.
HTTPS ✅ Used 🚫 Ignored When set to true, Create React App will run the development server in https mode.
WDS_SOCKET_HOST ✅ Used 🚫 Ignored When set, Create React App will run the development server with a custom websocket hostname for hot module reloading. Normally, webpack-dev-server defaults to window.location.hostname for the SockJS hostname. You may use this variable to start local development on more than one Create React App project at a time. See webpack-dev-server documentation for more details.
WDS_SOCKET_PATH ✅ Used 🚫 Ignored When set, Create React App will run the development server with a custom websocket path for hot module reloading. Normally, webpack-dev-server defaults to /ws for the SockJS pathname. You may use this variable to start local development on more than one Create React App project at a time. See webpack-dev-server documentation for more details.
WDS_SOCKET_PORT ✅ Used 🚫 Ignored When set, Create React App will run the development server with a custom websocket port for hot module reloading. Normally, webpack-dev-server defaults to window.location.port for the SockJS port. You may use this variable to start local development on more than one Create React App project at a time. See webpack-dev-server documentation for more details.
PUBLIC_URL ✅ Used ✅ Used Create React App assumes your application is hosted at the serving web server's root or a subpath as specified in package.json (homepage). Normally, Create React App ignores the hostname. You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application.
BUILD_PATH 🚫 Ignored ✅ Used By default, Create React App will output compiled assets to a /build directory adjacent to your /src. You may use this variable to specify a new path for Create React App to output assets. BUILD_PATH should be specified as a path relative to the root of your project.
CI ✅ Used ✅ Used When set to true, Create React App treats warnings as failures in the build. It also makes the test runner non-watching. Most CIs set this flag by default.
REACT_EDITOR ✅ Used 🚫 Ignored When an app crashes in development, you will see an error overlay with clickable stack trace. When you click on it, Create React App will try to determine the editor you are using based on currently running processes, and open the relevant source file. You can send a pull request to detect your editor of choice. Setting this environment variable overrides the automatic detection. If you do it, make sure your systems PATH environment variable points to your editor's bin folder. You can also set it to none to disable it completely.
CHOKIDAR_USEPOLLING ✅ Used 🚫 Ignored When set to true, the watcher runs in polling mode, as necessary inside a VM. Use this option if npm start isn't detecting changes.
GENERATE_SOURCEMAP 🚫 Ignored ✅ Used When set to false, source maps are not generated for a production build. This solves out of memory (OOM) issues on some smaller machines.
INLINE_RUNTIME_CHUNK 🚫 Ignored ✅ Used By default, Create React App will embed the runtime script into index.html during the production build. When set to false, the script will not be embedded and will be imported as usual. This is normally required when dealing with CSP.
IMAGE_INLINE_SIZE_LIMIT ✅ Used ✅ Used By default, images smaller than 10,000 bytes are encoded as a data URI in base64 and inlined in the CSS or JS build artifact. Set this to control the size limit in bytes. Setting it to 0 will disable the inlining of images.
FAST_REFRESH ✅ Used 🚫 Ignored When set to false, disables experimental support for Fast Refresh to allow you to tweak your components in real time without reloading the page.
TSC_COMPILE_ON_ERROR ✅ Used ✅ Used When set to true, you can run and properly build TypeScript projects even if there are TypeScript type check errors. These errors are printed as warnings in the terminal and/or browser console.
ESLINT_NO_DEV_ERRORS ✅ Used 🚫 Ignored When set to true, ESLint errors are converted to warnings during development. As a result, ESLint output will no longer appear in the error overlay.
DISABLE_ESLINT_PLUGIN ✅ Used ✅ Used When set to true, eslint-webpack-plugin will be completely disabled.
DISABLE_NEW_JSX_TRANSFORM ✅ Used ✅ Used When set to true, disables the new JSX transform introduced in React 17 and backported to React 16.14.0, 15.7.0, and 0.14.10. New projects will use a version of React that supports this by default but you may need to disable it in existing projects if you can't upgrade React.

+ WebComponents


    // --- Web Components in React
    class HelloMessage extends React.Component {
      render() {
        return <div>Hello <x-search>{this.props.name}</x-search>!</div>;
      }
    }

    // --- React in Web Components
    // this code will not work if you transform classes with Babel
    // include the custom-elements-es5-adapter
    // before you load web components to fix this issue
    class XSearch extends HTMLElement {
      connectedCallback() {
        const mountPoint = document.createElement('span');
        this.attachShadow({ mode: 'open' }).appendChild(mountPoint);
        const name = this.getAttribute('name');
        const url = 'https://www.google.com/search?q=' + encodeURIComponent(name);
        const root = createRoot(mountPoint);
        root.render(
          <a href={url}>{name}</a>
        );
      }
    }
    customElements.define('x-search', XSearch);
  

+ Other Libs

jQuery

    // easiest way to avoid conflicts is to prevent the React component from updating,
    // you can do this by rendering elements that React has no reason to update, like an empty div
    // attach a ref to the root DOM element
    // inside componentDidMount get a reference to it to pass to the jQuery plugin
    class SomePlugin extends React.Component {
      componentDidMount() {
        this.$el = $(this.el);
        this.$el.somePlugin();
      }
      componentWillUnmount() {
        this.$el.somePlugin('destroy');
      }
      render() {
        return <div ref={el => this.el = el} />;
      }
    }
    // --- integrating with jquery "Chosen" plugin
    // implement it as an uncontrolled component for simplicity
    class JqChosen extends React.Component {
      componentDidMount() {
        this.$el = $(this.el);
        this.$el.chosen();
        this.handleChange = this.handleChange.bind(this);
        this.$el.on('change', this.handleChange);
      }
      componentDidUpdate(prevProps) {
        if (prevProps.children !== this.props.children) {
          this.$el.trigger("chosen:updated");
        }
      }
      componentWillUnmount() {
        this.$el.off('change', this.handleChange);
        this.$el.chosen('destroy');
      }
      handleChange(e) {
        this.props.onChange(e.target.value);
      }
      render() {
        return (
          <div>
            <select className="Chosen-select" ref={el => this.el = el}>
              {this.props.children}
            </select>
          </div>
        );
      }
    }
    function JqExample() {
      return (
        <JqChosen onChange={value => console.log(value)}>
          <option>vanilla</option>
          <option>chocolate</option>
          <option>strawberry</option>
        </JqChosen>
      );
    }
    const jq_root = ReactDOM.createRoot(document.getElementById('jq_root'));
    jq_root.render(
      <JqExample />
    );
  
other view libraries

    // following jQuery implementation ...
    $('#container').html('<button id="btn">Say Hello</button>');
    $('#btn').click(function() {
      alert('Hello!');
    });
    // ... could be rewritten using a React component:
    function Button() {
      return <button id="btn">Say Hello</button>;
    }
    $('#btn').click(function() {
      alert('Hello!');
    });
    const root = ReactDOM.createRoot(document.getElementById('container'));
    root.render(<Button />);

    // --- dont rely on IDs because the same component can be rendered multiple times
    // register the click handler directly on the React button element
    function Button(props) {
      return <button onClick={props.onClick}>Say Hello</button>;
    }
    function HelloButton() {
      function handleClick() {
        alert('Hello!');
      }
      return <Button onClick={handleClick} />;
    }
    const root = ReactDOM.createRoot(document.getElementById('container'));
    root.render(<HelloButton />);

    // --- embedding react in a backbone view
    // create a Backbone view called ParagraphView
    // will override Backbone render() function to render a React Paragraph-component
    // into the DOM element provided by Backbone (this.el)
    function Paragraph(props) {
      return <p>{props.text}</p>;
    }
    const ParagraphView = Backbone.View.extend({
      initialize(options) {
        this.reactRoot = ReactDOM.createRoot(this.el);
      },
      render() {
        const text = this.model.get('text');
        this.reactRoot.render(<Paragraph text={text} />);
        return this;
      },
      remove() {
        this.reactRoot.unmount();
        Backbone.View.prototype.remove.call(this);
      }
    });
  
integrating with model layers

    // --- using backbone models in react components
    // simplest way to consume Backbone models and collections from a React component
    // is to listen to the various change events and manually force an update.
    // List component renders a Backbone collection,
    // using the Item component to render individual items:
    class Item extends React.Component {
      constructor(props) {
        super(props);
        this.handleChange = this.handleChange.bind(this);
      }
      handleChange() {
        this.forceUpdate();
      }
      componentDidMount() {
        this.props.model.on('change', this.handleChange);
      }
      componentWillUnmount() {
        this.props.model.off('change', this.handleChange);
      }
      render() {
        return <li>{this.props.model.get('text')}</li>;
      }
    }
    class List extends React.Component {
      constructor(props) {
        super(props);
        this.handleChange = this.handleChange();
      }
      handleChange() {
        this.forceUpdate();
      }
      componentDidMount() {
        this.props.collection.on('add', 'remove', this.handleChange);
      }
      componentWillUnmount() {
        this.props.collection.off('add', 'remove', this.handleChange);
      }
      render() {
        return (
          <ul>
            {this.props.collection.map(model => (
              <Item key={model.cid} model={model} />
            ))}
          </ul>
        );
      }
    }
    const collection = new Backbone.Collection([
      new Backbone.Model({ text: 'A' }),
      new Backbone.Model({ text: 'B' }),
      new Backbone.Model({ text: 'C' })
    ]);
    const ml_root_1 = ReactDOM.createRoot(document.getElementById('ml_root_1'));
    ml_root_1.render(<List collection={collection} />);

    // --- extracting data from backbone models
    // concentrate the knowledge about Backbone in as few parts of the code as possible
    // if you later plan to migrate to another data management solution
    // use HOC that extracts all attributes of a Backbone model into state,
    // passing the data to the wrapped component
    function connectToBackboneModel(WrappedComponent) {
      return class BackboneComponent extends React.Component {
        constructor(props) {
          super(props);
          this.state = Object.assign({}, props.model.attributes);
          this.handleChange = this.handleChange.bind(this);
        }
        componentDidMount() {
          this.props.model.on('change', this.handleChange);
        }
        componentWillReceiveProps(nextProps) {
          this.setState(Object.assign({}, nextProps.model.attributes));
          if (nextProps.model !== this.props.model) {
            this.props.model.off('change', this.handleChange);
            nextProps.model.on('change', this.handleChange);
          }
        }
        componentWillUnmount() {
          this.props.model.off('change', this.handleChange);
        }
        handleChange(model) {
          this.setState(model.changedAttributes());
        }
        render() {
          const propsExceptModel = Object.assign({}, this.props);
          delete propsExceptModel.model;
          return <WrappedComponent {...propsExceptModel} {...this.state} />;
        }
      }
    }

    function NameInput(props) {
      return (
        <p>
          <input value={props.firstName} onChange={props.handleChange} />
          <br />
          My name is {props.firstName}.
        </p>
      );
    }
    const BackboneNameInput = connectToBackboneModel(NameInput);
    function Example(props) {
      function handleChange(e) {
        props.model.set('firstName', e.target.value);
      }
      return (
        <BackboneNameInput
          model={props.model}
          handleChange={handleChange}
        />
      );
    }
    const model = new Backbone.Model({ firstName: 'Frodo' });
    const ml_root_2 = ReactDOM.createRoot(document.getElementById('ml_root_2'));
    ml_root_2.render(<Example model={model} />);
  

Advices

Example

    class ProductCategoryRow extends React.Component {
      render() {
        const category = this.props.category;
        return (
          <tr>
            <th colSpan="2">
              {category}
            </th>
          </tr>
        );
      }
    }

    class ProductRow extends React.Component {
      render() {
        const product = this.props.product;
        const name = product.stocked ?
          product.name :
          <span style={{color: 'red'}}>
            {product.name}
          </span>;

        return (
          <tr>
            <td>{name}</td>
            <td>{product.price}</td>
          </tr>
        );
      }
    }

    class ProductTable extends React.Component {
      render() {
        const filterText = this.props.filterText;
        const inStockOnly = this.props.inStockOnly;

        const rows = [];
        let lastCategory = null;

        this.props.products.forEach((product) => {
          if (product.name.indexOf(filterText) === -1) {
            return;
          }
          if (inStockOnly && !product.stocked) {
            return;
          }
          if (product.category !== lastCategory) {
            rows.push(
              <ProductCategoryRow
                category={product.category}
                key={product.category} />
            );
          }
          rows.push(
            <ProductRow
              product={product}
              key={product.name}
            />
          );
          lastCategory = product.category;
        });

        return (
          <table>
            <thead>
              <tr>
                <th>Name</th>
                <th>Price</th>
              </tr>
            </thead>
            <tbody>{rows}</tbody>
          </table>
        );
      }
    }

    class SearchBar extends React.Component {
      constructor(props) {
        super(props);
        this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
        this.handleInStockChange = this.handleInStockChange.bind(this);
      }

      handleFilterTextChange(e) {
        this.props.onFilterTextChange(e.target.value);
      }

      handleInStockChange(e) {
        this.props.onInStockChange(e.target.checked);
      }

      render() {
        return (
          <form>
            <input
              type="text"
              placeholder="Search..."
              value={this.props.filterText}
              onChange={this.handleFilterTextChange}
            />
            <p>
              <input
                type="checkbox"
                checked={this.props.inStockOnly}
                onChange={this.handleInStockChange}
              />
              {' '}
              Only show products in stock
            </p>
          </form>
        );
      }
    }

    class FilterableProductTable extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          filterText: '',
          inStockOnly: false
        };

        this.handleFilterTextChange = this.handleFilterTextChange.bind(this);
        this.handleInStockChange = this.handleInStockChange.bind(this);
      }

      handleFilterTextChange(filterText) {
        this.setState({
          filterText: filterText
        });
      }

      handleInStockChange(inStockOnly) {
        this.setState({
          inStockOnly: inStockOnly
        })
      }

      render() {
        return (
          <div>
            <SearchBar
              filterText={this.state.filterText}
              inStockOnly={this.state.inStockOnly}
              onFilterTextChange={this.handleFilterTextChange}
              onInStockChange={this.handleInStockChange}
            />
            <ProductTable
              products={this.props.products}
              filterText={this.state.filterText}
              inStockOnly={this.state.inStockOnly}
            />
          </div>
        );
      }
    }

    const PRODUCTS = [
      {category: 'Sporting Goods', price: '$49.99', stocked: true, name: 'Football'},
      {category: 'Sporting Goods', price: '$9.99', stocked: true, name: 'Baseball'},
      {category: 'Sporting Goods', price: '$29.99', stocked: false, name: 'Basketball'},
      {category: 'Electronics', price: '$99.99', stocked: true, name: 'iPod Touch'},
      {category: 'Electronics', price: '$399.99', stocked: false, name: 'iPhone 5'},
      {category: 'Electronics', price: '$199.99', stocked: true, name: 'Nexus 7'}
    ];

    const adv_root = ReactDOM.createRoot(document.getElementById('adv_root'));
    adv_root.render(<FilterableProductTable products={PRODUCTS} />);
  
Blur / Focus

    class BlurExample extends React.Component {
      constructor(props) {
        super(props);
        this.state = { isOpen: false };
        this.timeOutId = null;
        this.onClickHandler = this.onClickHandler.bind(this);
        this.onBlurHandler = this.onBlurHandler.bind(this);
        this.onFocusHandler = this.onFocusHandler.bind(this);
      }
      onClickHandler() {
        this.setState(currentState => ({
          isOpen: !currentState.isOpen
        }));
      }
      // We close the popover on the next tick by using setTimeout.
      // This is necessary because we need to first check if
      // another child of the element has received focus as
      // the blur event fires prior to the new focus event.
      onBlurHandler() {
        this.timeOutId = setTimeout(() => {
          this.setState({
            isOpen: false
          });
        });
      }
      // If a child receives focus, do not close the popover.
      onFocusHandler() {
        clearTimeout(this.timeOutId);
      }
      render() {
        // React assists us by bubbling the blur and
        // focus events to the parent.
        return (
          <div onBlur={this.onBlurHandler}
              onFocus={this.onFocusHandler}>
            <button onClick={this.onClickHandler}
                    aria-haspopup="true"
                    aria-expanded={this.state.isOpen}>
              Select an option
            </button>
            {this.state.isOpen ? (
              <ul>
                <li>Option 1</li>
                <li>Option 2</li>
                <li>Option 3</li>
              </ul>
            ) : null}
          </div>
        );
      }
    }
    const adv_root_2 = ReactDOM.createRoot(document.getElementById('adv_root_2'));
    adv_root_2.render(<BlurExample />);
  

Optimizing


    # PRODUCTION BUILD

    # --- uglify-js-brunch
    npm install --save-dev uglify-js-brunch # npm
    yarn add --dev uglify-js-brunch # Yarn
    # to create a production build, add the -p flag to the build command
    brunch build -p
    # dont pass -p flag in development

    # --- Browserify
    npm install --save-dev envify uglify-js uglifyify  # npm
    yarn add --dev envify uglify-js uglifyify  # Yarn
    # envify transform ensures the right build environment is set
    # uglifyify transform removes development imports
    # make them global (-g)
    # resulting bundle is piped to uglify-js for mangling:
    browserify ./index.js \
    -g [ envify --NODE_ENV production ] \
    -g uglifyify \
    | uglifyjs --compress --mangle > ./bundle.js

    # --- Rollup
    npm install --save-dev rollup-plugin-commonjs rollup-plugin-replace rollup-plugin-uglify
    yarn add --dev rollup-plugin-commonjs rollup-plugin-replace rollup-plugin-uglify
    # to create a production build,
    # make sure that you add these plugins (the order matters):
    plugins: [
      // ...
      require('rollup-plugin-replace')({
        'process.env.NODE_ENV': JSON.stringify('production')
      }),
      require('rollup-plugin-commonjs')(),
      require('rollup-plugin-uglify')(),
      // ...
    ]

    # --- webpack
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': JSON.stringify('production')
    }),
    new webpack.optimize.UglifyJsPlugin()
  

avoid reconciliation: shouldComponentUpdate | React.PureComponent


    // --- with shouldComponentUpdate
    class CounterButton extends React.Component {
      constructor(props) {
        super(props);
        this.state = {count: 1};
      }
      shouldComponentUpdate(nextProps, nextState) {
        if (this.props.color !== nextProps.color) {
          return true;
        }
        if (this.state.count !== nextState.count) {
          return true;
        }
        return false;
      }
      render() {
        return (
          <button
            color={this.props.color}
            onClick={() => this.setState(state => ({count: state.count + 1}))}>
            Count: {this.state.count}
          </button>
        );
      }
    }
    // --- or with React.PureComponent
    class CounterButton extends React.PureComponent {
      constructor(props) {
        super(props);
        this.state = {count: 1};
      }
      render() {
        return (
          <button
            color={this.props.color}
            onClick={() => this.setState(state => ({count: state.count + 1}))}>
            Count: {this.state.count}
          </button>
        );
      }
    }

    // code mutates the words array in the handleClick
    // old and new values of this.props.words will compare as equal,
    // even though the actual words in the array have changed !!!
    // ListOfWords will not update even though it has new words that should be rendered
    class ListOfWords extends React.PureComponent {
      render() {
        return <div>{this.props.words.join(',')}</div>;
      }
    }
    class WordAdder extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          words: ['marklar']
        };
        this.handleClick = this.handleClick.bind(this);
      }
      handleClick() {
        // this section is bad style and causes a bug
        const words = this.state.words;
        words.push('marklar');
        this.setState({words: words});
      }

      // --- avoid problem by avoiding mutation of values used as props or state
      handleClick() {
        this.setState(state => ({
          words: state.words.concat(['marklar'])
          // or
          words: [...state.words, 'marklar'],
        }));
      }
      // or without mutating the original objec use Object.assign
      function updateColorMap(colormap) {
        return Object.assign({}, colormap, {right: 'blue'});
        // same with object spread properties
        return {...colormap, right: 'blue'};
        // instead of:
        // colormap.right = 'blue';
      }

      render() {
        return (
          <div>
            <button onClick={this.handleClick} />
            <ListOfWords words={this.state.words} />
          </div>
        );
      }
    }
  

<Profiler>


    // can be added anywhere in a React tree
    // to measure the cost of rendering that part of the tree
    // requires two props: an id (string) and an onRender callback (function)
    // which React calls any time a component within the tree "commits" an update
    render(
      <Profiler id="application" onRender={onRenderCallback}>
        <App>
          <Navigation {...props} />
          <Main {...props} />
        </App>
      </Profiler>
    );
    // nested to measure different components within the same subtree:
    render(
      <App>
        <Profiler id="Panel" onRender={callback}>
          <Panel {...props}>
            <Profiler id="Content" onRender={callback}>
              <Content {...props} />
            </Profiler>
            <Profiler id="PreviewPane" onRender={callback}>
              <PreviewPane {...props} />
            </Profiler>
          </Panel>
        </Profiler>
      </App>
    );
  

Back to Main Page