Skip to content

Commit

Permalink
Set ref.current to undefined when element unmounts (fixes #17)
Browse files Browse the repository at this point in the history
  • Loading branch information
oamaok committed Dec 4, 2023
1 parent a6240fb commit 107f1b7
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 7 deletions.
1 change: 1 addition & 0 deletions build.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ terser
'useState',
'useRef',
'immutable',
'ref',
'current',
'Component',
'componentDidMount',
Expand Down
8 changes: 7 additions & 1 deletion src/kaiku.ts
Original file line number Diff line number Diff line change
Expand Up @@ -955,7 +955,9 @@ const updateFragmentInstance = (

if (__DEBUG__) {
if (nextkeys.has(key)) {
throw new Error('Duplicate key detected! Make sure no two sibling elements have the same key.')
throw new Error(
'Duplicate key detected! Make sure no two sibling elements have the same key.'
)
}
}

Expand Down Expand Up @@ -1376,6 +1378,10 @@ const unmountNodeInstance = (instance: NodeInstance<DefaultProps>) => {
}

case HtmlElementTag: {
if (typeof instance.props.ref !== 'undefined') {
instance.props.ref.current = undefined
}

destroyLazyUpdates(instance)
assert?.(instance.parentElement_)
instance.parentElement_.element_.removeChild(instance.element_)
Expand Down
45 changes: 39 additions & 6 deletions test/kaiku.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -1340,16 +1340,12 @@ describe('kaiku', () => {
effectCounter(state.counter)
return unsubCounter
})

return <div />
}

const App = () => {
return (
<div>
{state.isCompMounted ? <Comp /> : null}
</div>
)
return <div>{state.isCompMounted ? <Comp /> : null}</div>
}

render(<App />, rootNode)
Expand All @@ -1371,4 +1367,41 @@ describe('kaiku', () => {
expect(effectCounter).toHaveBeenCalledTimes(2)
expect(unsubCounter).toHaveBeenCalledTimes(2)
})

it('should set `ref.current` to `undefined` once HTML element unmounts', async () => {
const effectCounter = jest.fn()
const state = createState({ isDivMounted: false })

const App = () => {
const ref = useRef()

useEffect(() => {
effectCounter(ref.current)
})

return (
<div>
{state.isDivMounted ? (
<div ref={ref} id="el">
foo
</div>
) : null}
</div>
)
}

render(<App />, rootNode)
expect(effectCounter).toHaveBeenCalledTimes(1)
expect(effectCounter).toHaveBeenCalledWith(undefined)

state.isDivMounted = true
await nextTick()
expect(effectCounter).toHaveBeenCalledTimes(2)
expect(effectCounter).toHaveBeenCalledWith(rootNode.querySelector('#el'))

state.isDivMounted = false
await nextTick()
expect(effectCounter).toHaveBeenCalledTimes(3)
expect(effectCounter).toHaveBeenCalledWith(undefined)
})
})

0 comments on commit 107f1b7

Please sign in to comment.