Muhammad Faheem Akhtar
I'm a freelance JavaScript Developer who loves building cool things, especially Web Applications which solve business problems. I love trying new things, reading books, and wasting my time wondering about life and goals.
Error Handling in ReactJS
2nd Meetup
I'm Faheem
I'm a self-taught MERN Stack Developer
@mfaheemakhtar
mfaheemakhtar.com
* Code samples screenshots included.
1. Uncaught ReferenceError: myVariable is not defined.
Occurs when you try to use a variable which has not been defined.
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>
);
}
2. Uncaught TypeError: myArray.map is not a function.
Occurs when you try to use map over something which is not an array.
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>
);
}
3. Uncaught TypeError: Cannot read property 'name' of
undefined.
Occurs when you try to access a property of an undefined or null value.
3. Uncaught TypeError: Cannot read property 'name' of
undefined.
<List items={data} />
<List />
4. Uncaught Error: Objects are not valid as a React child.
Occurs when you try to render an object.
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>
);
ESLint
1. Install the extension.
2. Install ESLint.
npm install eslint babel-eslint -D
npx eslint --init
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"] }],
}
};
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
return (
<ol className="list">
{items.map(item => {
const { id, text } = item;
return (
<li className="list__item" key={id}>
{items}
</li>
);
})}
</ol>
);
#4
1. Install Flow.
npm install flow-bin babel-preset-flow -D
"presets": ["@babel/preset-env", "@babel/react", "flow"],
.babelrc
2. Run Flow.
npx flow init
npx flow
// @flow
Add to the top of the files.
defaultProps
type Props = {
foo: number,
};
class MyComponent extends Component<Props> {
static defaultProps = {
foo: 42,
};
...
}
Use 'prop-types'
List.defaultProps = {
items: [],
};
List.propTypes = {
items: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.number.isRequired,
text: PropTypes.string.isRequired,
}),
),
};
That's not a complete solution.
A * component becomes an error boundary if it defines either (or both) of the lifecycle methods
static getDerivedStateFromError() or componentDidCatch()
* Reserved for next slide.
So, what are Error Boundaries?
Are Error Boundaries
Class Components or Functional Components ?
Catch errors
What do they do?
But...
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
static getDerivedStateFromError
componentDidCatch
* 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>
);
Solving Error # 2
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>
);
Solving Error # 3
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>
);
Solving Error # 4
Solved Error # 4
Not Supported
Remember? Async code is not supported.
There are some workarounds.
.catch(error => {
this.setState(() => {
throw error;
});
});
render(
<ErrorBoundary>
<BrowserRouter>
<App />
</BrowserRouter>
</ErrorBoundary>,
document.getElementById('react'),
);
Wrap the App.
* Taken from Sentry.
Sentry
Sentry
By Muhammad Faheem Akhtar
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".
I'm a freelance JavaScript Developer who loves building cool things, especially Web Applications which solve business problems. I love trying new things, reading books, and wasting my time wondering about life and goals.