Categories
JavaScript React

Built-in React Hooks — useCallback, useMemo and Refs

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.

Categories
JavaScript React

Profile React App Performance with the Profile Component

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 profile a React app’s performance with the Profiler API.

Profiler API

The Profiler component measures how often a React app renders and what the cost of rendering is.

It helps identify parts of an app that are slow and may benefit from optimizations like memoization.

This component adds overhead, so it’s disabled in the production build.

Basic Usage

We can use it to measure performance as follows:

import React, { Profiler } from "react";  
import ReactDOM from "react-dom";  
import { unstable_trace as trace } from "scheduler/tracing";

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = { msg: "" };  
  } 

  onRender(  
    id,  
    phase,  
    actualDuration,  
    baseDuration,  
    startTime,  
    commitTime,  
    interactions  
  ) {  
    const performanceData = [  
      `id: ${id}`,  
      `phase: ${phase}`,  
      `actualDuration: ${actualDuration}`,  
      `baseDuration: ${baseDuration}`,  
      `startTime: ${startTime}`,  
      `commitTime: ${commitTime}`,  
      `interactions: ${JSON.stringify([...interactions])}`  
    ].join("\n");  
    console.log(performanceData);  
  } 

  componentDidMount() {  
    trace("initial render", performance.now(), () => {  
      this.setState({ msg: "foo" });  
    });  
  } 

  render() {  
    return (  
      <Profiler id="app" onRender={this.onRender.bind(this)}>  
        <p>{this.state.msg}</p>  
      </Profiler>  
    );  
  }  
}

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

In the code above, we have the Profiler component wrapped around our main app code in the rendr method.

We add an id prop so that we can identify what part of the React tree was committed if we’re using multiple profilers.

Also, we have an onRender prop which is set the our onRender method that we defined.

onRender is a callback that has the following parameters:

  • id — a string that we set to identify the part of the React component tree that we just committed.
  • phase — a string that can either have the value 'mout' or 'update' . This identifies whether the tree has just been mounted for the first time or re-rendered due to a change in props, state or hooks.
  • actualDuration — a number that shows the time spent rendering the Profiler and its descendants for the current update. This indicates how well the subtree makes use of memoization (e.g. with React.memo , useMemo , shouldComponentUpdate ). This should decrease significant after the initial mount since child components will only be re-rendered if props change
  • baseDuration — a number that indicates the duration of the most recent render time of each individual component within the Profiler tree. This estimates a worst-case cost of rendering
  • startTime — a timestamp when React began rendering the current update
  • commitTime — a timestamp when React committed to the current update. It’s shared between all profilers in a commit, enabling them to be grouped
  • interactions — a Set of interactions that were being traced when render or setState were called.

In the onRender method, we logged all the parameter values, and we get the following when App renders:

id: app  
phase: update  
actualDuration: 0.38499990478157997  
baseDuration: 0.045000109821558  
startTime: 908.5849998518825  
commitTime: 909.2250000685453  
interactions: [{"_count":1,"id":0,"name":"initial render","timestamp":906.7250001244247}]

The interactions output is from the trace method call. It’s tracking the time when the code inside the callback we passed as the last argument of trace we run.

This lets us associate the performance information with the events that caused the app to render.

From the output above, we can see that the render was caused by an update, and it’s because of the initial render interaction that we have in the componentDidMount lifecycle hook.

In the trace function call, we have the string with the name that we set to identify the interaction, performance.now() is a more precise version of Date.now() to get the current date-time which we pass in as the timestamp to start the trace.

The 3rd argument is a callback with the code that we want to trace the interaction for.

Conclusion

We can use the Profiler component to add performance tracking capabilities when we’re developing the app.

It’s useful because we can use it to see what parts of the React app is performing slowly and can benefit from caching or memoization.

To tracking interactions, i.e., the events that caused an update to be scheduled, we can use the unstable_trace function from the scheduler/tracing package to trace the timing of the interactions.

Categories
JavaScript React

Create React Error Boundary Components to Handle Errors Gracefully

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.

We can handle the error gracefully with error boundary components.

In this article, we’ll look at how to define and use them.

Error Boundaries

JavaScript inside components used to corrupt React’s internal state and cause cryptic errors to be emitted on the next renders.

These errors are always caused by earlier errors in the application code. React didn’t provide a way to handle them gracefully in components and recover from them.

We can use error boundaries to catch JavaScript errors anywhere in the child component tree, log those errors and display a fallback UI instead of crashing the app.

However, error boundaries don’t catch errors for event handlers, asynchronous code, server-side rendering, or errors thrown in the error boundary itself.

We can create an error boundary component by adding the static getDerivedStateFromError() or componentDidCatch() methods inside a class-based component.

For example, we can use it as follows:

class ErrorBoundary extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = { hasError: false };  
  } 

  static getDerivedStateFromError(error) {  
    return { hasError: true };  
  } 

  componentDidCatch(error, errorInfo) {  
    console.log(error, errorInfo);  
  } 

  render() {  
    if (this.state.hasError) {  
      return <h1>Error occured.</h1>;  
    } return this.props.children;  
  }  
}

class Button extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = { count: 0 };  
  }  
  increment() {  
    this.setState({ count: this.state.count + 1 });  
  }  
  render() {  
    if (this.state.count === 5) {  
      throw new Error("error");  
    } 

    return (  
      <>  
        <button onClick={this.increment.bind(this)}>Click Me</button>  
        <br />  
        <p>{this.state.count}</p>  
      </>  
    );  
  }  
}

class App extends React.Component {  
  render() {  
    return (  
      <div>  
        <ErrorBoundary>  
          <Button />  
        </ErrorBoundary>  
      </div>  
    );  
  }  
}

In the code above, we have the ErrorBoundary component, which has the componentDidCatch method to log the errors given by the parameters.

Then we added the static getDerivedStateFromError to set the hasError state to true if an error occurred.

In the render method, we render the error message if hasError state is true . Otherwise, we display the child components as usual.

In the Button component, we have a button element that increases the count state it’s clicked. We have an if statement for this.state.count which throws an error if it reaches 5.

Once it reaches 5, the ‘Error occurred’ message from the ErrorBoundary component will be shown since the error is thrown in the render method, which isn’t an event handler, async code, and other places error boundaries can’t catch.

As we can see, we placed the ErrorBoundary outside any code that catches errors. This way, ErrorBoundary can actually catch them.

During development, the whole stack trace will be displayed, we have to disable that in production. This will be done automatically when we make a production build with Create React App.

Catching Errors Inside Event Handlers

We have to use try/catch block to catch errors in event handlers.

For example, we can write the following code to catch those:

class App extends React.Component {  
  constructor(props) {  
    super(props);  
    this.state = { error: null, count: 0 };  
    this.handleClick = this.handleClick.bind(this);  
  } 

  handleClick() {  
    try {  
      if (this.state.count === 5) {  
        throw new Error("error");  
      }  
      this.setState({ count: this.state.count + 1 });  
    } catch (error) {  
      this.setState({ error });  
    }  
  } 
  
  render() {  
    if (this.state.error) {  
      return <h1>Error occurred.</h1>;  
    }  
    return (  
      <button onClick={this.handleClick}>Count: {this.state.count}</button>  
    );  
  }  
}

In the handleClick method, we have an if statement that throws an error if this.state.count is 5.

If an error is thrown, the catch block will set the error state to the error object.

This will then render the ‘Error occurred’ message instead of the button to increase the count state.

Conclusion

We can use error boundary components to handle errors gracefully and log them.

To create an error boundary component, we add a static getDerivedStateFromError() or componentDidCatch() method to do that.

We use componentDidCatch to log errors and getDerivedStateFromError to render a fallback UI.

We wrap the error component around child components that may throw errors.

Error boundary can catch errors in places other than async code, event handlers, server-side rendering code, or errors thrown in the error boundary itself.

Categories
JavaScript React

Basic React Hooks – useContext and useReducer

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 the useContext and useReducer hooks.

useContext

We can use the useContext hook to read shared data shared from a React context. It accepts the context object returned from React.createContext as an argument and returns the current context value.

The current context value is determined by the value prop of the nearest context provider.

We can use it as follows:

const ColorContext = React.createContext("green");function Button() {  
  const color = React.useContext(ColorContext);  
  return <button style={{ color }}>button</button>;  
}function App() {  
  return (  
    <>  
      <ColorContext.Provider value="blue">  
        <Button />  
      </ColorContext.Provider>  
    </>  
  );  
}

In the code above, we created a new React context with:

const ColorContext = React.createContext("green");

Then in App , we wrapped out Button with the ColorContext.Provider with the value prop set to blue .

Then in Button , we have:

const color = React.useContext(ColorContext);

to get the value passed in from the ColorContext.Provider and set it to color .

Finally, we set the color style of the button with the color ‘s value.

A component calling useContext will always re-render when the context value changes. If re-rendering is expensive, then we can optimize it with memoization.

useContext is the React hooks version of Context.Consumer .

useReducer

This hook is an alternative to useState . It accepts a reducer function of type (state, action) => newState .

useReducer is preferable to useState when we have complex state logic that involves multiple sub-values or when the next state depends on the previous one.

It also lets us optimize performance for components that trigger deep updates because we can pass dispatch down instead of callbacks.

For example, we can write:

const INCREMENT = "INCREMENT";  
const DECREMENT = "DECREMENT";function reducer(state, action) {  
  switch (action.type) {  
    case INCREMENT:  
      return { count: state.count + 1 };  
    case DECREMENT:  
      return { count: state.count - 1 };  
    default:  
      throw new Error();  
  }  
}

function App() {  
  const [state, dispatch] = React.useReducer(reducer, { count: 0 });  
  return (  
    <>  
      Count: {state.count}  
      <button onClick={() => dispatch({ type: DECREMENT })}>Decrement</button>  
      <button onClick={() => dispatch({ type: INCREMENT })}>Increment</button>  
    </>  
  );  
}

In the code above, we have our reducer which returns the new state depends on the action.type ‘s value. In this case, it’s either 'INCREMENT' or 'DECREMENT' .

If it’s ‘INCREMENT’ , we return { count: state.count + 1 } .

If it’s ‘DECREMENT’ , we return { count: state.count — 1 } .

Otherwise, we throw an error.

Then in App , we call useReducer by passing in a reducer as the first argument and the initial state as the second argument.

Then we get the state object, which has the current state object and a dispatch function, which we can call with an action object, which has the type property with the value being one of ‘INCREMENT’ or ‘DECREMENT' .

We used the dispatch function in the buttons to update the state.

Finally, we display the latest state in state.count .

Lazy initialization

We can pass in a function to the 3rd argument of useReducer to initialize the state lazily.

The initial state will be set to init(initialArg) .

For instance, we can rewrite the previous example as follows:

const init = initialCount => {  
  return { count: initialCount };  
};

const INCREMENT = "INCREMENT";  
const DECREMENT = "DECREMENT";

function reducer(state, action) {  
  switch (action.type) {  
    case INCREMENT:  
      return { count: state.count + 1 };  
    case DECREMENT:  
      return { count: state.count - 1 };  
    default:  
      throw new Error();  
  }  
}
function App() {  
  const [state, dispatch] = React.useReducer(reducer, 0, init);  
  return (  
    <>  
      Count: {state.count}  
      <button onClick={() => dispatch({ type: DECREMENT })}>Decrement</button>  
      <button onClick={() => dispatch({ type: INCREMENT })}>Increment</button>  
    </>  
  );  
}

First, we have:

const init = initialCount => {  
  return { count: initialCount };  
};

to return the initial state.

And instead of writing:

React.useReducer(reducer, { count: 0 });

We have:

React.useReducer(reducer, 0, init);

0 is passed in as the initialCount of init .

Then the rest of the code is the same as before.

Bailing out of a dispatch

If the same value is returned from a Reducer hook is the same as the current state, React will bail out without rendering the children or firing effects.

The comparison is done using the Object.is() algorithm.

If we’re doing expensive operations while rendering, we can optimize it with useMemo .

Conclusion

The useContext hook is the React hook equivalent of the Context.Consumer of the Context API.

It takes a React context object as the argument and returns the current value from the context.

useReducer is an alternative version of useState for more complex state changes.

It takes in a reducer as the first argument and the initial state object as the second argument.

It can also take the same first argument, and take the initial state value as the second argument, and a function to return the initial state as the 3rd argument. This combination lets React set the initial state lazily.