React

Error Handling in ReactJS

KHI

2nd Meetup

I'm Faheem

I'm a self-taught MERN Stack Developer

@mfaheemakhtar

mfaheemakhtar.com

Things I'll be talking about!

  • Some common JavaScript errors
  • How to prevent them
  • Error Boundaries
  • Tracking exceptions

 

 

 

         * Code samples screenshots included.

Errors

Some Common JavaScript Errors

1. Uncaught ReferenceError: myVariable is not defined.

Occurs when you try to use a variable which has not been defined.

Some Common JavaScript Errors

1. Uncaught ReferenceError: myVariable is not defined.

  render() {
    const { name } = this.state;

    return (
      <div className="container">
        <div className="content">
          <h1 className="heading">{`${nam}'s to-do list for * days.`} </h1>
          <List items={data} />
        </div>
      </div>
    );
  }

Some Common JavaScript Errors

2. Uncaught TypeError: myArray.map is not a function.

Occurs when you try to use map over something which is not an array.

Some Common JavaScript Errors

2. Uncaught TypeError: myArray.map is not a function.

render() {
    const { name } = this.state;

    return (
      <div className="container">
        <div className="content">
          <h1 className="heading">{`${name}'s to-do list for * days.`} </h1>
          <List items={{ data }} />
        </div>
      </div>
    );
  }

Some Common JavaScript Errors

3. Uncaught TypeError: Cannot read property 'name' of

              undefined.

Occurs when you try to access a property of an undefined or null value.

Some Common JavaScript Errors

3. Uncaught TypeError: Cannot read property 'name' of

              undefined.


<List items={data} />

<List />

Some Common JavaScript Errors

4. Uncaught Error: Objects are not valid as a React child.

Occurs when you try to render an object.

Some Common JavaScript Errors

4. Uncaught Error: Objects are not valid as a React child.

return (
    <ol className="list">
      {items.map(item => {
        const { id, text } = item;

        return (
          <li className="list__item" key={id}>
            {items}
          </li>
        );
      })}
    </ol>
  );

Preventing Errors

ESLint

Linting

Let's use ESLint

1. Install the extension.

Let's use ESLint

2. Install ESLint.

npm install eslint babel-eslint -D

npx eslint --init

Let's use ESLint

3. Configure ESLint.

module.exports = {
  extends: "airbnb"
};
module.exports = {
  extends: "airbnb",
  parser: "babel-eslint",
  rules: {
    "react/jsx-one-expression-per-line": "literal",
    "react/jsx-filename-extension": [1, { extensions: [".js", ".jsx"] }],
  }
};

Here it is

  render() {
    const { name } = this.state;

    return (
      <div className="container">
        <div className="content">
          <h1 className="heading">{`${nam}'s to-do list for * days.`} </h1>
          <List items={data} />
        </div>
      </div>
    );
  }

#1

Here too

return (
    <ol className="list">
      {items.map(item => {
        const { id, text } = item;

        return (
          <li className="list__item" key={id}>
            {items}
          </li>
        );
      })}
    </ol>
  );

#4

Type Checking

Let's use Flow

1. Install Flow.

npm install flow-bin babel-preset-flow -D
"presets": ["@babel/preset-env", "@babel/react", "flow"],

.babelrc

Let's use Flow

2. Run Flow.

npx flow init
npx flow
// @flow

Add to the top of the files.

Let's use Flow

defaultProps

type Props = {
  foo: number,
};

class MyComponent extends Component<Props> {
  static defaultProps = {
    foo: 42,
  };

  ...
}

An Alternative

Use 'prop-types'

List.defaultProps = {
  items: [],
};

List.propTypes = {
  items: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.number.isRequired,
      text: PropTypes.string.isRequired,
    }),
  ),
};

But...

That's not a complete solution.

So, What is the solution?

Error Boundaries

A * component becomes an error boundary if it defines either (or both) of the lifecycle methods

static getDerivedStateFromError() or componentDidCatch() 

* Reserved for next slide.

Error Boundaries

So, what are Error Boundaries?

Are Error Boundaries

 

Class Components or Functional Components ?

Error Boundaries

Catch errors

  • Rendering
  • Lifecycle methods
  • Constructors of the whole tree below them

Error Boundaries

What do they do?

Error Boundaries

But...

Error Boundaries

class ErrorBoundary extends Component {
  state = {
    hasError: false,
  };

  static getDerivedStateFromError(error) {
    return { hasError: true };        // No side-effects here.
  }

  componentDidCatch(error, info) {
    // Side-effects here.
  }

  render() {
    const { hasError } = this.state;
    const { children, message } = this.props;

    if (hasError) {
      return (
        <div><p>{message}</p></div>
      );
    }
    return children;
  }
}

Let's create an Error Boundary

So, what is

static getDerivedStateFromError

And...

componentDidCatch

Fallback UI

* Taken from Sentry.

return (
  <div className="container">
    <div className="content">
      <ErrorBoundary>
        <h1 className="heading">{`${name}'s to-do list for * days.`} </h1>
        <List items={{ data }} />
      </ErrorBoundary>
    </div>
  </div>
);
return (
  <div className="container">
    <div className="content">
      <h1 className="heading">{`${name}'s to-do list for * days.`} </h1>
      <List items={{ data }} />
    </div>
  </div>
);

Keep it simple

Solving Error # 2

Keep it simple

Solved Error # 2

return (
  <div className="container">
    <div className="content">
      <ErrorBoundary message="Oh man! To-do list heading has crashed!">
        <h1 className="heading">{`${name}'s to-do list for * days.`} </h1>
      </ErrorBoundary>
      <ErrorBoundary message="Looks like your list has crashed.">
        <List />
      </ErrorBoundary>
    </div>
  </div>
);
return (
  <div className="container">
    <div className="content">
      <h1 className="heading">{`${name}'s to-do list for * days.`} </h1>
      <List />
    </div>
  </div>
);

Let's solve another one

Solving Error # 3

Let's solve another one

Solved Error # 3

return (
  <ErrorBoundary>
    <div className="container">
      <div className="content">
        <ErrorBoundary message="Oh man! To-do list heading has crashed!">
          <h1 className="heading">{`${name}'s to-do list for * days.`} </h1>
        </ErrorBoundary>
        <ErrorBoundary message="Looks like your list has crashed.">
          <List items={data} />
        </ErrorBoundary>
      </div>
    </div>
  </ErrorBoundary>
);
return (
  <div className="container">
    <div className="content">
      <h1 className="heading">{`${name}'s to-do list for * days.`} </h1>
      <List />
    </div>
  </div>
);

One more

Solving Error # 4

One more

Solved Error # 4

What about Promises?

 Not Supported

Remember? Async code is not supported.

But...

There are some workarounds.

.catch(error => {
  this.setState(() => {
    throw error;
  });
});
render(
  <ErrorBoundary>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </ErrorBoundary>,

  document.getElementById('react'),
);

We can also

Wrap the App.

Tracking Exceptions

* Taken from Sentry.

Tracking Exceptions

Sentry

Tracking Exceptions

Sentry

Thank you!

Error Handling in ReactJS | ReactKHI - Meetup 2

By Muhammad Faheem Akhtar

Error Handling in ReactJS | ReactKHI - Meetup 2

This is the slide I used for my talk in the 2nd ReactKHI meetup. It was an amazing experience to share my experience on "Error Handling in ReactJS".

  • 263