Skip to content

fix: compare pass-through props in day-cell memo comparators - #19

Merged
dogmar merged 1 commit into
mainfrom
fix/m1-memo-comparators
Jun 15, 2026
Merged

fix: compare pass-through props in day-cell memo comparators#19
dogmar merged 1 commit into
mainfrom
fix/m1-memo-comparators

Conversation

@dogmar

@dogmar dogmar commented Jun 15, 2026

Copy link
Copy Markdown
Collaborator

Audit medium M1.

Problem

DayCellInstance and DayButtonInner are memo'd with custom comparators (dayCellInstancePropsAreEqual, dayButtonInnerPropsAreEqual). Both compared only date / render / columnIndex and the _derivedState fields — but both components accept arbitrary spread props ([key: string]: unknown) and forward them onto the rendered element (mergeProps(defaultProps, otherProps)). Those pass-through props (className, style, onPointerDown, data-*, …) were never compared, so they froze at first render: a consumer changing className on DayCellTemplate/DayButton saw no update unless a compared field also changed.

Fix

A shared passThroughPropsEqual(prev, next, handledKeys) does a shallow compare of the remaining props, skipping the explicitly-handled keys and children (a fresh React element every render — never usefully comparable, matching the existing intent). It's AND-ed into both comparators, so genuine pass-through changes now re-render while stable props stay memoized.

Tests

The comparators are now exported and unit-tested (day-cell.test.tsx): changing a className / handler / data-* returns false (RED before the fix — they returned true); unchanged props return true; children differences are still ignored; derived-state changes still return false.

vp run ready: lint+typecheck 0/0, all suites green — including the grid.perf memoization tests (stable pass-through props, so no extra re-renders).

🤖 Generated with Claude Code

dayCellInstancePropsAreEqual / dayButtonInnerPropsAreEqual compared only
date/render/columnIndex and the derived state, ignoring the arbitrary
spread props (className, style, event handlers, data-*) the components
forward onto their element. Those were frozen at first render — a
consumer's changed className/handler wouldn't apply unless a compared
field happened to change too.

Add a shared passThroughPropsEqual shallow comparison (skipping the
explicitly-handled keys and children, which is a fresh element each
render) and AND it into both comparators. The comparators are now
exported and unit-tested.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@dogmar
dogmar merged commit a0df447 into main Jun 15, 2026
6 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 2.0.1 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant