26
loading...
This website collects cookies to deliver better user experience
try {
throw new Error('Hello, World! My name is error!');
} catch (error) {
console.error(error);
}
function React(data) {
return UI;
}
const UI = React({ name: 'John' });
try {
const UI = React({ name: 'John' });
} catch (error) {
console.error(error);
}
ReactDOM.render(
<App />,
document.getElementById("app")
);
<App />
and all of its components. Hm, the best place to wrap our app with try/catch:try {
ReactDOM.render(
<App />,
document.getElementById("app")
);
} catch (error) {
console.error("React render error: ", error);
}
<App />
into the DOM. All other things is not about ReactDOM.render.// We can use a class here too
// Just wrap an inner of the render method
const App = () => {
try {
return (
<div>
<ChildWithError />
</div>
);
} catch (error) {
console.error('App error handler: ', error);
return <FallbackUI/>;
}
}
<ChildWithError/>
will be 4, this component will throw an error inside render. But there won't be any message in console, no any fallback UI. Wait, WAT? We all know, that:<div>
<ChildWithError />
</div>
React.createElement(
'div',
null,
React.createElement(ChildWithError, null)
)
// The source: https://github.com/facebook/react/blob/main/packages/react/src/ReactElement.js#L148
const element = {
// This tag allows us to uniquely identify this as a React Element
$$typeof: REACT_ELEMENT_TYPE, // Built-in properties that belong on the element
type: type,
key: key,
ref: ref,
props: props, // Record the component responsible for creating this element.
_owner: owner,
};
<App />
. There is an object, which describe <ChildWithError />
inside props.children of that <App />
. You can see it by yourself, just try to console.log it.<App />
is rendered, <ChildWithError />
intended to be rendered too, right inside that <App />
. <App />
. I can say at the moment, React will call all render functions by itself, somewhere in its own context. I'll describe this idea lately.try {
Promise.resolve().then(() => {
throw new Error('wow!');
});
} catch (error) {
console.log('Error from catch: ', error);
}
<ChildWithError />
to {ChildWithError()} inside <App />
. It means, we will call ChildWithError's render by ourselves. And voila! You will see an error message in the console and the fallback UI in the browser!function Counter() {
const [count, setCount] = React.useState(0)
const increment = () => setCount(c => c + 1)
return <button onClick={increment}>{count}</button>
}
function App() {
const [items, setItems] = React.useState([])
const addItem = () => setItems(i => [...i, {id: i.length}])
return (
<div>
<button onClick={addItem}>Add Item</button>
<div>{items.map(Counter)}</div>
</div>
)
}
<App />
, which has internal state (via useState). The value of that state is shared via React.context. <App />
renders <Child />
. <Child />
is wrapped with HOC memo. <Child />
renders <GrandChild />
.<Child />
. In my idea, this try catch has to handle all errors from <GrandChild />
. And <GrandChild />
has a specific logic to throw an error, when the value from the context will be more that 3. There is a scheme:<App />
. It means, <App />
is used as Error Boundary.<App />
and <GrandChild />
will be rerendered. <App />
— cause of the state change, <GrandChild />
— cause of the context value change. Looks like there is no any <Child />
between <App />
and <GrandChild />
. It's because of HOC memo. Let's highlight all rerendered components:<App />
two times more, an error will be thrown inside <GrandChild />
. But <Child />
do not know about anything around with its try/catch.Hi. My name is React.
Thanks for the instructions from JSX about what to render.
You can have a coffee, while I am doing my job.
try {
*React is working*
} catch (error) {
Oops, a new error.
Ok, I will try to find a parent of the component
with that error.
Maybe that parent can do something with it.
All other work will be saved!
}