I'm not that good at JavaScript classes (as I use functional components almost exclusively). I have a slight modified ErrorBoundary class that I've mostly pasted from the React docs.
I have code that uses this ErrorBoundary that I can successfully call the resetError method I have defined in addExtraProps. I'm wanting to reset the "this.state.error" to false from this function. I think it's a JavaScript thing, nothing to do with React.
You can see I have commented out this.setState({ hasError: false }) as that does not work because the external function calling this has no access to this (I assume).
Appreciate any help.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true, message: error?.message, status: error?.status };
}
render() {
function addExtraProps(Component, extraProps) {
return (
<Component.type
{...Component.props}
resetError={() => {
debugger;
// THE BELOW CODE DOES NOT WORK AS WE DON'T HAVE ACCESS TO
// "THIS" IN A CALL FROM AN EXTERNAL FUNCTION.
//
//this.setState({ hasError: false });
}}
{...extraProps}
/>
);
}
if (this.state.hasError) {
return addExtraProps(this.props.fallback, {
errorMessage: this.state.message,
errorStatus: this.state.status,
});
}
return this.props.children;
}
}
Also, though there is a lot in between, this is what the call looks like that is executing the resetError:
function ErrorBoundaryFallback({ errorMessage, errorStatus, resetError }) {
return (
<>
<hr />
<div className="city-details">
<div>
<b>Error:</b> {errorMessage} {" ..... "} <b>Status:</b> {errorStatus}
</div>
</div>
<button onClick={() => resetError()}>Try again with resetError</button>
</>
);
}
CodePudding user response:
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
//----- this is what i meant by binding in the constructor
this.changeState = this.changeState.bind(this)
}
//----- this is the new method
changeState() {
this.setState({ hasError: false });
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true, message: error?.message, status: error?.status };
}
render() {
function addExtraProps(Component, extraProps) {
return (
<Component.type
{...Component.props}
resetError={this.changeState}
{...extraProps}
/>
);
}
if (this.state.hasError) {
return addExtraProps(this.props.fallback, {
errorMessage: this.state.message,
errorStatus: this.state.status,
});
}
return this.props.children;
}
}
CodePudding user response:
The problem lies in the part where you create function addExtraProps. That function breaks your entry to this from ErrorBoundry class.
You need to create that function as arrow, and you will be all good.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true, message: error?.message, status: error?.status };
}
render() {
const addExtraProps = (Component, extraProps) => {
return (
<Component.type
{...Component.props}
resetError={() => {
this.setState({ hasError: false });
}}
{...extraProps}
/>
);
}
if (this.state.hasError) {
return addExtraProps(this.props.fallback, {
errorMessage: this.state.message,
errorStatus: this.state.status,
});
}
return this.props.children;
}
}
In the other case you can extract that setState logic into a method of your class and set it there, and than assign it to that resetError callback:
class ErrorBoundary extends React.Component {
// ...
resetError = () => {
this.setState({ hasError: false});
}
render() {
const addExtraProps = (Component, extraProps) => {
return (
<Component.type
{...Component.props}
resetError={resetError}
{...extraProps}
/>
);
}
// ...
}
}
I would suggest to always use arrow function when dealing with classes.
Here you can see an example of arrow method where i assign value to resetError class method as arrow function. There is no need to do this.resetError.bind(this) in the constructor. That was the old way.
If you only use plain JS (no TypeScript), you would possibly need to add this babel plugin to be able to use arrow methods. (it is maybe included on the newer versions of babel, i used this a long time ago)
