Categories
JavaScript React

Lazy Load Your React Code With Code-Splitting

React is a library for creating front-end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we’ll look at how to make apps load faster by splitting code so that only the parts that are needed will load.


Code-Splitting

We need code-splitting so that product React bundles won’t be too big. As our apps get bigger, the production bundles will also get bigger and take longer to load if we don’t split them and load them only when needed.

Create React App has code-splitting support built-in. We can use the lazy and import functions from React to achieve this.

For example, we can use those functions as follows:

Foo.js:

import React from "react";export default function Foo() {  
  return <div>foo</div>;  
}

App.js:

In the code above, we have Foo.js with the Foo component.

Then, in App.js, we have the App component that has Suspense to load the fallback. UI has the Foo import loads. We need this since Foo is loaded at runtime.

React.lazy loads the Foo component at runtime instead of at build time. It also splits the code from the bundle into a separate file so that each bundled file is smaller.

We’ll get an error telling us to add a fallback UI with the Suspense component if it’s missing.

The fallback prop accepts any React element that we want to render while waiting for the component to load. We can place Suspense anywhere above the lazy component.

Wrapping multiple elements in a single Suspense element also works.


Error Boundaries

To fail gracefully when other modules fail to load, such as where network failure occurs, we can use error boundary components.

To use them, we wrap them around the Suspense component as follows:

ErrorBoundary.js:

Foo.js:

import React from "react";

export default function Foo() {  
  return <div>foo</div>;  
}

App.js:

In the code above, we added the ErrorBoundary component in ErrorBoundary.js.

Then, in App, we wrapped it around our Suspense component, which lets us catch any errors that occur when loading the Foo component.


Route-Based Code-Splitting

Many React apps are single-page apps. They’ll have routes to map URLs to components.

We can split code based on routes. For example, we can incorporate React Router routes into our app and split code based on routes as follows:

Foo.js:

import React from "react";

export default function Foo() {  
  return <div>foo</div>;  
}

Bar.js:

import React from "react";

export default function Bar() {  
  return <div>bar</div>;  
}

App.js:

In the example above, we add the Router component around all our components.

We put the Routes inside the Suspense component so that they can be lazy-loaded. That is, they load only when we load the route in our browser.

This is also why we need the Suspense component around the routes. We need the fallback UI so that it’ll be shown when the routes are loading.


Named Exports

React.lazy only supports default exports. If our module uses named exports, then we have to create an intermediate module that re-exports it as default.

For example, we can arrange our code as follows:

Foo.js:

import React from "react";

export const Foo = function() {  
  return <div>foo</div>;  
};

FooDefault.js:

import { Foo } from "./Foo";

export default Foo;

App.js:

import React, { Suspense } from "react";
const FooComponent = React.lazy(() => import("./Foo"));
export default function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <FooComponent />
    </Suspense>
  );
}

In the code above, we have FooDefault.js that exports Foo as a default export.

Then, we imported it in App.js with React.lazy.


Conclusion

Code-splitting is easy with Create React App and React. React has the lazy method to import components on the fly.

We need a fallback UI so that we can see something when the dynamically imported component loads.

Error boundaries are also supported and we can use it to gracefully fail when a dynamically imported component fails to load.

Code-splitting is also supported by React Router. React.lazy is smart enough to split code by route.

Categories
JavaScript React

Creating Sidebars with React Router

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

To build single-page apps, we have to have some way to map URLs to the React component to display.

In this article, we’ll look at how to create sidebars with route content only displaying in a portion of the screen with React Router.

Creating Sidebar

We can easily create a fixed sidebar on one side of the screen while displaying route content on the other.

To do this, we just need to add our sidebar on one side with links and the Switch and Route components on the other.

For example, we can write the following code to achieve this effect:

import React from "react";  
import ReactDOM from "react-dom";  
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";

const routes = [  
  {  
    path: "/",  
    exact: true,  
    sidebar: () => <div>home</div>,  
    main: () => <h2>Home</h2>  
  },  
  {  
    path: "/foo",  
    sidebar: () => <div>foo</div>,  
    main: () => <h2>Bubblegum</h2>  
  },  
  {  
    path: "/shoelbaraces",  
    sidebar: () => <div>bar</div>,  
    main: () => <h2>Shoelaces</h2>  
  }  
];

function App() {  
  return (  
    <Router>  
      <div style={{ display: "flex" }}>  
        <div  
          style={{  
            padding: "10px",  
            width: "40%",  
            background: "pink"  
          }}  
        >  
          <ul style={{ listStyleType: "none", padding: 0 }}>  
            <li>  
              <Link to="/">Home</Link>  
            </li>  
            <li>  
              <Link to="/foo">Foo</Link>  
            </li>  
            <li>  
              <Link to="/bar">Bar</Link>  
            </li>  
          </ul> <Switch>  
            {routes.map((route, index) => (  
              <Route  
                key={index}  
                path={route.path}  
                exact={route.exact}  
                children={<route.sidebar />}  
              />  
            ))}  
          </Switch>  
        </div> <div style={{ flex: 1, padding: "10px" }}>  
          <Switch>  
            {routes.map((route, index) => (  
              <Route  
                key={index}  
                path={route.path}  
                exact={route.exact}  
                children={<route.main />}  
              />  
            ))}  
          </Switch>  
        </div>  
      </div>  
    </Router>  
  );  
}

const rootElement = document.getElementById("root");  
ReactDOM.render(<App />, rootElement);

In the code above, we have the sidebar in the top of App . And we have the routes array as follows:

const routes = [  
  {  
    path: "/",  
    exact: true,  
    sidebar: () => <div>home</div>,  
    main: () => <h2>Home</h2>  
  },  
  {  
    path: "/foo",  
    sidebar: () => <div>foo</div>,  
    main: () => <h2>Bubblegum</h2>  
  },  
  {  
    path: "/shoelbaraces",  
    sidebar: () => <div>bar</div>,  
    main: () => <h2>Shoelaces</h2>  
  }  
];

In the outermost div of App , we have display: 'flex' style to display the sidebar and the route content side by side, with the sidebar of the left and the route content on the right.

The sidebar is composed of the following code in App :

<div style={{ padding: "10px", width: "40%", background: "#f0f0f0" }}>  
    <ul style={{ listStyleType: "none", padding: 0 }}>  
        <li>  
            <Link to="/">Home</Link>  
        </li>  
        <li>  
            <Link to="/foo">Foo</Link>  
        </li>  
        <li>  
            <Link to="/bar">Bar</Link>  
        </li>  
    </ul>  
    <Switch>  
        {routes.map((route, index) => (  
        <Route key={index} path={route.path} exact={route.exact} children={<route.sidebar />} /> ))}  
    </Switch>  
</div>

In the code above, we have the ul element to display the Link s, which we can click on the show the route that we want.

In the Switch component, we have the routes array mapped to Route s that we want to display in the sidebar.

We want to display the component we set as the value of the sidebar in each entry of routes . Therefore, we set children to that.

In the routes array, we have the route with path set to '/' has the exact property set to true .

We have to do this so that React Router won’t direct all routes that start with a / to the ‘home’ route. This is because React Router doesn’t look at the other routes once it found a match.

If the match isn’t exact, then it’ll take anything that starts with a / as the correct match. In this case, it’ll be the first route.

The right side is composed of the following code:

<div style={{ flex: 1, padding: "10px" }}>  
    <Switch>  
        {routes.map((route, index) => (  
        <Route key={index} path={route.path} exact={route.exact} children={<route.main />} /> ))}  
    </Switch>  
</div>

The code above maps the routes array again to Route s, but we set the children prop to the components set to the main property instead of sidebar .

Conclusion

We can create a sidebar easily by using flexbox and the Switch and Route components.

As long as we have Switch and Route components in only one portion of the screen, the route content will only be displayed on that part of the screen.

Flexbox lets us display items side by side without hassle.

Categories
JavaScript React

Built-in React Hooks —useLayoutEffect and useDebugValue

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we look at the useLayoutEffect and useDebugValue hooks.

useLayoutEffect

useLayoutEffect has an identical signature to useEffect , but it fires synchronously after all DOM mutations are done.

This is useful for reading layout from the DOM and synchronously re-render.

Updates inside useLayoutEffect will be flushed synchronously before the browser has a chance to paint.

To prevent blocking visual updates, we should use useEffect whenever possible.

useLayoutEffect fires in the same phase as componentDidMount and componentDidUpdate .

We should only use useLayoutEffect if useEffect isn’t working properly.

If server rendering is used, the useLayoutEffect nor useEffect are run until the JavaScript is downloaded.

React warns when server-rendered component contains useLayourEffect .

To exclude components that need layout effects from server-rendered HTML, we render it conditionally with showChild && <Child /> and defer showing it with useEffect(() => { setShowChild(true); }, []).

Then the UI won’t appear broken before rendering is done.

For example, we can render synchronous with useLayoutEffect as follows:

function App() {  
  const [value, setValue] = React.useState(0);  
  React.useLayoutEffect(() => {  
    if (value === 0) {  
      setValue(10 + Math.random() * 200);  
    }  
  }, [value]); 

  return (  
    <>  
      <button onClick={() => setValue(0)}>Random Value</button>  
      <p>{value}</p>  
    </>  
  );  
}

Since value is set initially to 0, we want to update that first before rendering, so we use useLayoutEffect hook and call setValue in the callback.

Also, since we set value to 0 when clicking the button, we want to only show the value when value when it’s not 0, so useLayoutEffect will prevent 0 from being shown.

useDebugValue

useDebugValue is used to display a label for custom hooks in React DevTools.

It takes any value that we want to display.

For example, we can use it as follows:

import React, { useEffect, useState } from "react";  
import ReactDOM from "react-dom";  
const useDelayedMessage = (msg, delay) => {  
  const [message, setMessage] = useState("");  
  useEffect(() => {  
    setTimeout(() => {  
      setMessage(msg);  
    }, delay);  
  });  
  React.useDebugValue(message ? "Message Set" : "Message not set");  
  return message;  
};

function App() {  
  const delayedMessage = useDelayedMessage("foo", 1500);  
  return <div>{delayedMessage}</div>;  
}

Since we have:

React.useDebugValue(message ? "Message Set" : "Message not set");

in React DevTools, we’ll see the Message not set message when the page first loads, and then when message is set after the delay , then we see Message set .

This hook is useful for custom hooks that are part of shared libraries

Defer formatting debug values

In some cases formatting, a value for display may be an expensive operation.

Therefore, useDebugValue accepts a formatting function as an optional second parameter. The function is only called if the hooks are inspected.

It receives the debug value as a parameter and returns the formatted display value.

For example, we can write:

import React, { useEffect, useState } from "react";  
import ReactDOM from "react-dom";  
const useDelayedMessage = (msg, delay) => {  
  const [message, setMessage] = useState("");  
  useEffect(() => {  
    setTimeout(() => {  
      setMessage(msg);  
    }, delay);  
  });  
  React.useDebugValue(message, message =>  
    message ? "Message Set" : "Message not set"  
  );  
  return message;  
};

function App() {  
  const delayedMessage = useDelayedMessage("foo", 1500);  
  return <div>{delayedMessage}</div>;  
}

In the code above, we have:

React.useDebugValue(message, message =>  
    message ? "Message Set" : "Message not set"  
  );

which runs the formatting function in the second argument when it’s inspected.

The message parameter has the same value as message returned from useState .

Conclusion

We can use the useLayoutEffect hook to synchronous run code after all DOM mutations are done.

useDebugValue hook is handy for debugging with React DevTools since it lets us display something in the DevTools console as the hook runs.

Categories
JavaScript React

Built-in React Hooks — useCallback, useMemo and Refs

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

In this article, we look at the useCallback, useMemo, useRef, and useImperativeHandle hooks.

useCallback

We can use the useCallback hook to return a memoized callback.

It takes a callback function as the first argument, and an array of value that changes for the callback in the first argument to be called.

This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.

For example, we can use it as follows:

function App() {  
  const [count, setCount] = React.useState(0);  
  const memoizedIncrement = React.useCallback(() => {  
    setCount(count => count + 1);  
  }, [setCount]); 

  const memoizedDecrement = React.useCallback(() => {  
    setCount(count => count - 1);  
  }, [setCount]); 

  return (  
    <>  
      Count: {count}  
      <button onClick={memoizedDecrement}>Decrement</button>  
      <button onClick={memoizedIncrement}>Increment</button>  
    </>  
  );  
}

In the code above, we used the useCallback hook to create 2 new functions to let us update the count . We have setCount(count => count + 1) and setCount(count => count — 1) in the callback of useCallback .

And we cache the setCount function so that React won’t always return a new one in every render unless setCount changes.

Then in the onClick handlers, we use them as usual.

Every value referenced inside the callback should also appear in the dependencies array.

useMemo

useMemo caches values that are computed from a function. The first argument is a function that computes the value, and the second argument is an array with the dependencies that are used to compute the returned value.

useMemo runs during rendering. It’s used as a performance optimization. React may forget previously memoized value and recalculate them on the next render in cases it needs to free memory for offscreen components for example.

Therefore, we should write code that works with useMemo and then add it to optimize performance.

For example, we can use it as follows:

function App() {  
  const [count, setCount] = React.useState(0);  
  const doubleCount = React.useMemo(() => 2 * count, [count]); 

  return (  
    <>  
      Double Count: {doubleCount}  
      <button onClick={() => setCount(oldCount => oldCount - 1)}>  
        Decrement  
      </button>  
      <button onClick={() => setCount(oldCount => oldCount + 1)}>  
        Increment  
      </button>  
    </>  
  );  
}

In the code above, we use the useMemo hook by passing in a function that returns 2 times the count , and pass in an array with count inside as the 2nd argument.

useMemo caches the value of doubleCount until count changes.

Then we pass in functions to call setCount in the onClick props of the buttons.

Finally, we display the doubleCount value on the screen, which updates when we click on the buttons.

useRef

The useRef hook returns a mutable ref whose current property is initialized to the passed argument. The returned object will persist for the full lifetime of the component.

For example, we can use it as follows:

function App() {  
  const inputEl = React.useRef(null);  
  React.useEffect(() => {  
    inputEl.current.focus();  
  }, []);  
  return (  
    <>  
      <input ref={inputEl} type="text" />  
    </>  
  );  
}

In the code above, we created the inputEl ref by calling useRef with the value null .

Then once we pass inputEl as the ref of the input, we set inputEl.current to the input element’s DOM object.

Therefore, we can call focus on it to focus the input in the useEffect callback, which is only run during initial render, since we passed in an empty array to the second argument.

It can be used to keep any mutable value around. useRef creates a plain Javascript object.

The only difference between useRef() and creating a { current: ... } object ourselves is that useRef will give us the same ref object on every render.

useRef doesn’t notify us when the content changes.

useImperativeHandle

useImperativeHandle customizes the instance value that’s exposed to parent components when using a ref .

For example, we can use it as follows:

function Button(props, ref) {  
  const buttonRef = React.useRef();  
  React.useImperativeHandle(ref, () => ({  
    focus: () => {  
      buttonRef.current.focus();  
    }  
  }));  
  return <button ref={buttonRef}>Button</button>;  
}  
Button = React.forwardRef(Button);

function App() {  
  const buttonRef = React.useRef(null);  
  React.useEffect(() => {  
    buttonRef.current.focus();  
  }, []);  
  return (  
    <>  
      <Button ref={buttonRef} />  
    </>  
  );  
}

In the code above, we have:

React.useImperativeHandle(ref, () => ({  
    focus: () => {  
      buttonRef.current.focus();  
    }  
  }));

to customize the focus method to call buttonRef.current.focus(); .

Then we pass buttonRef in Button to the button ‘s ref as follows:

<button ref={buttonRef}>Button</button>;

Then to make the ref accessible to App , we run:

Button = React.forwardRef(Button);

Then in App , we run:

const buttonRef = React.useRef(null);

to create the ref and:

<Button ref={buttonRef} />

to set buttonRef to our exposed Button ‘s buttonRef after calling forwardRef to expose it to App .

Then we run:

React.useEffect(() => {  
    buttonRef.current.focus();  
  }, \[\]);

to focus the Button component’s button when App first renders.

Conclusion

We can use the useCallback hook to return a memoized callback, which we can call. It takes a callback as an argument and an array of dependencies that were referenced in the callback as the second argument.

useMemo caches values that are computed. It takes a function that returns a value as the first argument, and an array of values that the function depends on as the second argument.

useRef returns a mutable object whose current property is initialized to the initial value and can be passed into the ref prop of an element to set current to the DOM element.

useImperativeHandle customizes the behavior of the DOM element methods of the element that’s exposed via forwardRef to the parent component.

Categories
JavaScript React

Introduction to React Router

React is a library for creating front end views. It has a big ecosystem of libraries that work with it. Also, we can use it to enhance existing apps.

To build single-page apps, we have to have some way to map URLs to the React component to display.

In this article, we’ll look at the basic usage of React Router.

Installation

To use React Router, we have to install it. We can do that by running:

npm i react-router-dom

Basic Usage

React Router has a few basic components.

BrowserRouter

First, there’s the BrowserRouter to do the routing with the HTML5 history API.

It takes a few props:

  • basename — a string prop for the base URL for all locations.
  • getUserConfirmation — a function prop we use to confirm navigation. Defaults to using window.confirm .
  • forceRefresh — a boolean prop that’s true if we want a full refresh on page navigation. It’s useful for imitating traditional server-render apps.
  • keyLength — a number prop that sets the length of location.key . Defaults to 6.
  • children — a React component to render. Before React 16, we can only use a single child element. If we want to render more than one element, we can wrap it in a div.

Switch

Next, there’s the Switch component. It renders the first child Route or Redirect that matches the location.

Switch renders a route exclusively. Route that matches the location renders inclusively.

Switch will only pick one Route to render.

Route

The Route component is the most important component in React Router.

It’s used to map URLs to components and takes the following props:

  • component — we pass in the component to map the URL to by passing in a component to it.
  • render — this prop takes a function that returns something that we want to render.
  • children — a function prop that lets us render something when the path matches Route ‘s path and render something else otherwise.
  • path — a string or array of strings that are paths to match.
  • exact — a boolean prop to that’s true if we want to render only if a path matches exactly.
  • strict — boolean prop that’s true is we only want to match a path with a trailing slash only when the URL entered has a trailing slash. It has no effect when there’re additional URL segments in location.pathname
  • location — an object prop that tries to match its path in the current history location.
  • sensitive — a boolean prop that true if the path is case-sensitive.

Link

The Link component provides accessible navigation around our app.

It takes the following props:

  • to — a string prop with the path that we want to go to. It’s created by concatenating location’s pathname, search and hash properties.
  • to can also be an object that has the pathname, search, state and hash properties. The pathname is a string that has the path to link to. search is a string of the query parameters, hash is a hash top put in the URL, state is the state to persist to the location.
  • to can also be a function which takes the currentlocation as the argument and returns the location representation as a string as an object.
  • replace — a boolean prop that replaces the current entry in the history stack instead of adding one if true
  • innerRef — a function or ref object that we shouldn’t need if we’re using React Router 5.1 or later with React 16. It lets us access the ref of the component.
  • We can any other attribute to the a tag like title , id , className , etc.

Example

We can use the components above together as follows:

import React from "react";  
import ReactDOM from "react-dom";  
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";  
function Home() {  
  return <h2>Home</h2>;  
}

function Foo() {  
  return <h2>Foo</h2>;  
}

function Bar() {  
  return <h2>Bar</h2>;  
}

function App() {  
  return (  
    <Router>  
      <div>  
        <ul>  
          <li>  
            <Link to="/">Home</Link>  
          </li>  
          <li>  
            <Link to="/foo">Foo</Link>  
          </li>  
          <li>  
            <Link to="/bar">Bar</Link>  
          </li>  
        </ul>  
        <Switch>  
          <Route exact path="/">  
            <Home />  
          </Route>  
          <Route path="/foo">  
            <Foo />  
          </Route>  
          <Route path="/bar">  
            <Bar />  
          </Route>  
        </Switch>  
      </div>  
    </Router>  
  );  
}

const rootElement = document.getElementById("root");  
ReactDOM.render(<App />, rootElement);

In the code above, we have the Home , Foo , and Bar components which display some text.

Then we add Router in App and put all our Route s inside so when we click on the Link s, they’ll display the component we specified.

We have:

<Switch>  
    <Route exact path="/">  
        <Home />  
    </Route>  
    <Route path="/foo">  
        <Foo />  
    </Route>  
    <Route path="/bar">  
        <Bar />  
    </Route>  
</Switch>

In the Switch , we have exact in the first Route to only show Home when we go to / .

Then we define 2 more Route s to show Foo when we go to /foo and Bar when we go to /bar .

Conclusion

We can use React Router to map URLs to components. This lets us create a single-page app since we render components according to URLs on the client-side.

Therefore, we’ll have a self-contained app that works on its own without the server rendering things when we type in URLs.

We have the Link to render links, Route to map URLs to components. Router wraps around anything that needs routing.

Switch renders the first child Route or Redirect that matches the location.