Skip to content

Commit

Permalink
Clear ref to element if ref prop is not present on next render
Browse files Browse the repository at this point in the history
  • Loading branch information
oamaok committed Sep 23, 2024
1 parent 7342132 commit 19b2134
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 5 deletions.
11 changes: 6 additions & 5 deletions src/kaiku.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1055,7 +1055,6 @@ const updateElementProperty = (
}
}

// TODO: Should be inlined. See above.
const updateElementStyle = (
element: HTMLElement | SVGElement,
property: string,
Expand Down Expand Up @@ -1258,13 +1257,15 @@ const updateHtmlElementInstance = (
// Handle properties other than `style`
for (const key of keys) {
if (key === 'style') continue

// TODO: Special case access to classsnames
if (instance.props_[key] === nextProps[key]) continue
if (key === 'key') continue
if (instance.props_[key] === nextProps[key]) continue

if (key === 'ref') {
nextProps[key]!.current = instance.element_
if (key in nextProps) {
nextProps[key]!.current = instance.element_
} else {
instance.props_[key]!.current = undefined
}
continue
}

Expand Down
37 changes: 37 additions & 0 deletions test/kaiku.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1599,6 +1599,43 @@ describe('kaiku', () => {
expect(effectCounter).toHaveBeenCalledWith(undefined)
})

it('should set `ref.current` to `undefined` if element is re-used but not unmounted', async () => {
const effectCounter = jest.fn()
const state = createState({ isRef: false })

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

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

return (
<div>
{state.isRef ? (
<div ref={ref} />
) : (
<div />
)}
</div>
)
}

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

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

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

it('should handle changes in element event handlers', async () => {
const handlerA = jest.fn()
const handlerB = jest.fn()
Expand Down

0 comments on commit 19b2134

Please sign in to comment.