Skip to content

Commit ee81c53

Browse files
author
Tane Morgan
authored
Merge pull request tanem#188 from tanem/issue-187
Ensure setState isn't called when the component is unmounted
2 parents 07f398c + 6c9ed55 commit ee81c53

File tree

2 files changed

+41
-9
lines changed

2 files changed

+41
-9
lines changed

src/index.tsx

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ export default class ReactSVG extends React.Component<
7272

7373
state = this.initialState
7474

75+
// tslint:disable-next-line:variable-name
76+
_isMounted = false
77+
7578
container?: HTMLSpanElement | HTMLDivElement | null
7679

7780
svgWrapper?: HTMLSpanElement | HTMLDivElement | null
@@ -108,15 +111,19 @@ export default class ReactSVG extends React.Component<
108111
this.removeSVG()
109112
}
110113

111-
this.setState(
112-
() => ({
113-
hasError: !!error,
114-
isLoading: false
115-
}),
116-
() => {
117-
onInjected(error, svg)
118-
}
119-
)
114+
// TODO: It'd be better to cleanly unsubscribe from SVGInjector
115+
// callbacks instead of tracking a property like this.
116+
if (this._isMounted) {
117+
this.setState(
118+
() => ({
119+
hasError: !!error,
120+
isLoading: false
121+
}),
122+
() => {
123+
onInjected(error, svg)
124+
}
125+
)
126+
}
120127
}
121128

122129
SVGInjector(this.svgWrapper.firstChild, {
@@ -135,6 +142,7 @@ export default class ReactSVG extends React.Component<
135142
}
136143

137144
componentDidMount() {
145+
this._isMounted = true
138146
this.renderSVG()
139147
}
140148

@@ -151,6 +159,7 @@ export default class ReactSVG extends React.Component<
151159
}
152160

153161
componentWillUnmount() {
162+
this._isMounted = false
154163
this.removeSVG()
155164
}
156165

test/browser.spec.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,4 +246,27 @@ describe('while running in a browser environment', () => {
246246

247247
expect(wrapper.html()).toMatchSnapshot()
248248
})
249+
250+
// TODO: When we have the ability to cleanly unsubscribe from SVGInjector
251+
// callbacks, we can update this dicey test to instead ensure the callbacks
252+
// aren't called.
253+
it('does not call setState when the component is unmounted', () => {
254+
/* tslint:disable:no-console */
255+
const orglFn = console.error
256+
console.error = jest.fn()
257+
258+
wrapper = mount(
259+
<ReactSVG src={`http://localhost/${faker.random.uuid()}.svg`} />
260+
)
261+
262+
wrapper.unmount()
263+
264+
requests[0].respond(200, {}, source)
265+
jest.runAllTimers()
266+
267+
expect(console.error).not.toHaveBeenCalled()
268+
269+
console.error = orglFn
270+
/* tslint:enable:no-console */
271+
})
249272
})

0 commit comments

Comments
 (0)