Skip to content

Commit

Permalink
feat: pass arguments to onReset callback (#51)
Browse files Browse the repository at this point in the history
  • Loading branch information
kentcdodds authored May 1, 2020
1 parent 4e240df commit c30eda2
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 6 deletions.
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,11 @@ state (which will result in rendering the `children` again). You should use this
to ensure that re-rendering the children will not result in a repeat of the same
error happening again.

`onReset` will be called with whatever `resetErrorBoundary` is called with. In
the case of `resetKeys`, it's called with the `prevResetKeys` and the
`resetKeys`. This can help you differentiate between a reset that occurred due
to a "try again" button click and one trigged by a `resetKeys` change.

### `resetKeys`

Sometimes an error happens as a result of local state to the component that's
Expand Down
33 changes: 30 additions & 3 deletions src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,14 +252,30 @@ test('requires either a fallback, fallbackRender, or FallbackComponent', () => {
})

test('supports automatic reset of error boundary when resetKeys change', () => {
const handleReset = jest.fn()
const TRY_AGAIN_ARG1 = 'TRY_AGAIN_ARG1'
const TRY_AGAIN_ARG2 = 'TRY_AGAIN_ARG2'
function App() {
const [explode, setExplode] = React.useState(false)
return (
<div>
<button onClick={() => setExplode(e => !e)}>toggle explode</button>
<ErrorBoundary
FallbackComponent={ErrorFallback}
onReset={() => setExplode(false)}
fallbackRender={({resetErrorBoundary}) => (
<div role="alert">
<button
onClick={() =>
resetErrorBoundary(TRY_AGAIN_ARG1, TRY_AGAIN_ARG2)
}
>
Try again
</button>
</div>
)}
onReset={(...args) => {
setExplode(false)
handleReset(...args)
}}
resetKeys={[explode]}
>
{explode ? <Bomb /> : null}
Expand All @@ -268,21 +284,32 @@ test('supports automatic reset of error boundary when resetKeys change', () => {
)
}
render(<App />)
userEvent.click(screen.getByText('toggle explode'))

// blow it up
userEvent.click(screen.getByText('toggle explode'))
screen.getByRole('alert')
expect(console.error).toHaveBeenCalledTimes(2)
console.error.mockClear()

// recover via try again button
userEvent.click(screen.getByText(/try again/i))
expect(screen.queryByRole('alert')).not.toBeInTheDocument()
expect(console.error).not.toHaveBeenCalled()
expect(handleReset).toHaveBeenCalledWith(TRY_AGAIN_ARG1, TRY_AGAIN_ARG2)
expect(handleReset).toHaveBeenCalledTimes(1)
handleReset.mockClear()

// blow it up again
userEvent.click(screen.getByText('toggle explode'))
screen.getByRole('alert')
expect(console.error).toHaveBeenCalledTimes(2)
console.error.mockClear()

// recover via resetKeys change
userEvent.click(screen.getByText('toggle explode'))
expect(handleReset).toHaveBeenCalledWith([true], [false])
expect(handleReset).toHaveBeenCalledTimes(1)
handleReset.mockClear()
expect(screen.queryByRole('alert')).not.toBeInTheDocument()
expect(console.error).not.toHaveBeenCalled()
})
Expand Down
6 changes: 3 additions & 3 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ const changedArray = (a = [], b = []) =>
const initialState = {error: null, info: null}
class ErrorBoundary extends React.Component {
state = initialState
resetErrorBoundary = () => {
this.props.onReset?.()
resetErrorBoundary = (...args) => {
this.props.onReset?.(...args)
this.setState(initialState)
}

Expand All @@ -20,7 +20,7 @@ class ErrorBoundary extends React.Component {
const {error} = this.state
const {resetKeys} = this.props
if (error !== null && changedArray(prevProps.resetKeys, resetKeys)) {
this.resetErrorBoundary()
this.resetErrorBoundary(prevProps.resetKeys, resetKeys)
}
}

Expand Down

0 comments on commit c30eda2

Please sign in to comment.