У меня есть компонент, который в своем методе рендеринга генерирует ошибку.
Выше в дереве компонент connect() привязан к ресурсу, использующему react-redux для извлечения данных, и у меня есть другие HOCS и т. д. (внедрение классов и т. д.).
Компонент использует границу ошибки в случае (скажем) отсутствия свойства в предоставленном ему ресурсе (распространенная проблема).
Я привел минимальный пример, обращаясь к свойству undefined, чтобы воспроизвести ту же ошибку:
import React from 'react'
// An Error Boundary which returns either a fallback component (if supplied to props) or (default) an empty div, instead of screwing up the whole tree
class ErrorBoundary extends React.Component {
constructor(props) {
super(props)
this.state = {
hasError: false,
}
}
static getDerivedStateFromError(error) {
return { hasError: true }
}
componentDidCatch(error, info) {
this.setState({ hasError: true })
console.info('do stuff with', error, info)
}
render() {
console.info('RENDERING ERROR BOUNDARY WITH STATE:', this.state)
if (this.state.hasError) {
if (this.props.fallback) {
return (this.props.fallback)
}
return (<div />)
}
return this.props.children
}
}
class MyComponent extends React.Component {
render() {
const resource = undefined
return (
<ErrorBoundary>
<p>{resource.missingProperty}</p>
</ErrorBoundary>
)
}
}
export default MyComponent
Конечно, попытка отрисовать компонент генерирует следующую трассировку стека:
Uncaught TypeError: Cannot read property 'missingProperty' of undefined
at MyComponent.render (index.jsx:58)
at finishClassComponent (react-dom.development.js:15141)
at updateClassComponent (react-dom.development.js:15096)
at beginWork (react-dom.development.js:15980)
at performUnitOfWork (react-dom.development.js:19102)
at workLoop (react-dom.development.js:19143)
at HTMLUnknownElement.callCallback (react-dom.development.js:147)
at Object.invokeGuardedCallbackDev (react-dom.development.js:196)
at invokeGuardedCallback (react-dom.development.js:250)
at replayUnitOfWork (react-dom.development.js:18350)
at renderRoot (react-dom.development.js:19261)
at performWorkOnRoot (react-dom.development.js:20165)
at performWork (react-dom.development.js:20075)
at performSyncWork (react-dom.development.js:20049)
at requestWork (react-dom.development.js:19904)
at scheduleWork (react-dom.development.js:19711)
at Object.enqueueSetState (react-dom.development.js:12936)
at Connect.push../node_modules/react/cjs/react.development.js.Component.setState (react.development.js:356)
at Connect.onStateChange (connectAdvanced.js:205)
at Object.notify (Subscription.js:23)
at Subscription.notifyNestedSubs (Subscription.js:62)
at Connect.onStateChange (connectAdvanced.js:202)
at Object.notify (Subscription.js:23)
at Subscription.notifyNestedSubs (Subscription.js:62)
at Connect.onStateChange (connectAdvanced.js:202)
at Object.dispatch (createStore.js:175)
at e (<anonymous>:1:40553)
at asyncDispatchMiddleware.js:33
at middleware.js:13
at middlewareCamel.js:13
at middlewareDate.js:34
at _callee$ (middleware.js:285)
at tryCatch (runtime.js:63)
at Generator.invoke [as _invoke] (runtime.js:290)
at Generator.prototype.<computed> [as next] (runtime.js:116)
at step (asyncToGenerator.js:21)
at asyncToGenerator.js:32
The above error occurred in the <MyComponent> component:
in MyComponent (created by Connect(MyComponent))
in Connect(MyComponent) (at withCachedResource.js:43)
in _class (created by StreamField)
in div (at streamfield.js:17)
in StreamField (at StoryDrawer.js:34)
in div (created by Grid)
in Grid (created by WithStyles(Grid))
in WithStyles(Grid) (at GridItem.jsx:20)
in GridItem (created by WithStyles(GridItem))
in WithStyles(GridItem) (at StoryDrawer.js:33)
in div (created by Grid)
in Grid (created by WithStyles(Grid))
in WithStyles(Grid) (at GridContainer.jsx:20)
in GridContainer (created by WithStyles(GridContainer))
in WithStyles(GridContainer) (at StoryDrawer.js:26)
in StoryDrawer (created by WithStyles(StoryDrawer))
in WithStyles(StoryDrawer) (created by Connect(WithStyles(StoryDrawer)))
in Connect(WithStyles(StoryDrawer)) (at Map.js:264)
in div (created by Paper)
in Paper (created by WithStyles(Paper))
in WithStyles(Paper) (created by Drawer)
in Transition (created by Slide)
in EventListener (created by Slide)
in Slide (created by WithTheme(Slide))
in WithTheme(Slide) (created by Drawer)
in RootRef (created by Modal)
in div (created by Modal)
in Portal (created by Modal)
in Modal (created by WithStyles(Modal))
in WithStyles(Modal) (created by Drawer)
in Drawer (created by WithStyles(Drawer))
in WithStyles(Drawer) (at Map.js:252)
in div (at Map.js:153)
in Map (created by WithStyles(Map))
in WithStyles(Map) (created by Connect(WithStyles(Map)))
in Connect(WithStyles(Map)) (created by AddUrlProps(Connect(WithStyles(Map))))
in AddUrlProps(Connect(WithStyles(Map))) (at MapPage.jsx:24)
in div (at FullArea/index.js:43)
in FullArea (at MapPage.jsx:22)
in div (at MapPage.jsx:21)
in MapPage (created by WithStyles(MapPage))
in WithStyles(MapPage) (created by Connect(WithStyles(MapPage)))
in Connect(WithStyles(MapPage)) (created by Route)
in Route (at App.js:33)
in Switch (at App.js:25)
in div (at App.js:23)
in App (at src/index.js:32)
in RouterToUrlQuery (at src/index.js:31)
in Router (created by ConnectedRouter)
in ConnectedRouter (at src/index.js:30)
in Provider (at src/index.js:29)
Consider adding an error boundary to your tree to customize error handling behavior.
Visit ... to learn more about error boundaries.
Что СУПЕР странно, так это то, что метод ErrorBoundary render() никогда не выводит на консоль. Как будто этой оболочки просто не существует, и реакция полностью игнорирует ее, напрямую отображая только дочерние элементы. Я понятия не имею, как это вообще возможно.
Я отправил это на рабочий сервер, и там появилось то же самое, поэтому я не думаю, что это связано с конфигурацией разработки и производства.
Я схожу с ума? Я совершенно неправильно понял, для чего нужны границы ошибок React?
Может ли что-то более высокое в стеке вызовов как-то мешать обработчику ошибок?
Покажите принятому ответу немного любви своими голосами, ребята. Исправленное решение (теперь ясно, что я его вижу) заключается в том, что компонент, вызывающий ошибку, должен быть обернут, а не просто элементы, которые определяет компонент. Исправленный код:
import React from 'react'
class MyComponent extends React.Component {
render() {
const resource = undefined
return (
<p>{resource.missingProperty}</p>
)
}
}
class MyBoundedComponent extends React.Component {
render() {
return (
<ErrorBoundary>
<MyComponent />
</ErrorBoundary>
)
}
}
export default MyBoundedComponent



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


ErrorBoundry никогда не визуализируется, потому что метод рендеринга MyComponent никогда не возвращается.
Ошибка возникает при каждом рендере.
render в реакции создает представление дерева элементов, которое будет использоваться в реакции, ошибка, которую вы вызвали, замыкает этот процесс.
Вы можете заставить свой пример работать, обернув границу ошибки поверх MyComponent, а не внутри него (в компоненте, который отображает MyComponent
Это скорее различие между createElement, что делает ваш код в функции рендеринга, и когда реакция вызывает render
Так как же мне защититься от ошибки, возникающей при первом выполнении метода render()?
Ах! Теперь я понимаю! Спасибо @thedude - ты сегодня самый лучший чувак. Модифицированный код и отправленный на промежуточный сервер; теперь он работает должным образом как в среде разработки, так и в рабочей среде. Дэн Абрамов рекомендует не помещать границы ошибок в HOC, но я склонен не согласиться с этим, поскольку я хочу, чтобы мой компонент и его обернутый обработчик ошибок были инкапсулированы, а не обрабатывались ошибки уровнем выше в коде. Тем не менее, это дискуссия для другого дня, и теперь эта проблема решена. Спасибо!
Э... хорошо. Спасибо @thedude, я чувствую, что это первый шаг в моем обучении. Строго говоря, ошибка (в реальной жизни) на самом деле возникает при рендеринге первый, а не при каждом рендеринге. Не означает ли это, что границы ошибок полезны только в том случае, если ошибка возникает при последующих рендерах?