-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[charts] Allow customizing shape in scatter charts #16640
base: master
Are you sure you want to change the base?
[charts] Allow customizing shape in scatter charts #16640
Conversation
Deploy preview: https://deploy-preview-16640--material-ui-x.netlify.app/ Updated pages: |
CodSpeed Performance ReportMerging #16640 will degrade performances by 22.58%Comparing Summary
Benchmarks breakdown
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments, if there are other places you want input, let me know
onClick?: (event: React.MouseEvent<SVGElement, MouseEvent>) => void; | ||
} | ||
|
||
export interface ScatterMarkerOwnerState { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can remove this and merge the props into the ScatterMarkerProps
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used in Scatter.types.ts
and on ScatterMarkerProps
, so it's probably better to keep it to avoid duplication.
I'll remove it if we have only one usage.
c663548
to
529ac2a
Compare
A lot of the times, the slots are passed to the top component, which means you should be able to pass it around to the |
0062831
to
ba795ba
Compare
ba795ba
to
d729245
Compare
id: '2', | ||
label: 'Series B', | ||
data: data.map((v) => ({ x: v.x1, y: v.y2, id: v.id })), | ||
markerSize: 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't love it that markerSize
is just a scale. I think it would be better if it were the width in pixels of a marker, for example.
@JCQuintas @alexfauquette is there a procedure to analyze and fix these performance regressions? When do we just acknowledge them on CodSpeed? When running the benchmarks locally against a real browser (
This PR:
By the way, I think there's some room for improvement to the way we benchmark. Here's some things I noticed:
I'll see if I find the time to fix these. |
These are improvements, but they are not necessary, we are checking relative performance, not total. We don't care about the seconds there, only the % change. If the relative performance changes then something is wrong. We can still add these changes to a different issue though, so we pick them up. |
We usually acknowledge it when we are ok with the changes. There is no hard rule. @alexfauquette worked on improving the circle marker performance, so he will probably have some points to share |
Yeah, I agree, but if I can't replicate the 20% difference locally, doesn't that mean that the issue might not be in this PR but rather in how we run our benchmarks? I think the local benchmarks are more realistic since they rely on a real browser rather than JSDOM.
Sure, created it here. |
Managed to find the root cause of the failing test. It is a consequence of two factors:
Initially, I didn't wrap I'll focus on fixing Next, I'll take a look at how to fix the issue with |
// If it is a plain function which accepts two arguments, we don't need to pass a ref because the component doesn't expect it | ||
const shouldPassRef = Component.length >= 2; | ||
|
||
if (process.env.NODE_ENV !== 'production') { | ||
OutComponent.displayName = `${name}.slots.${slotPropName}`; | ||
Component.displayName = `${name}.slots.${slotPropName}`; | ||
} | ||
|
||
return <OutComponent {...outProps} ref={ref} />; | ||
return <Component {...outProps} ref={shouldPassRef ? ref : undefined} />; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JCQuintas what do you think of this change?
I'm proposing it to fix the issue of creating a new component on render. You can read more about it here.
Not sure if this only works for React 19 since ref is now a normal prop, but if you think the approach makes sense then I'll test it across different versions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, also ensure it is working when passing both reffed and non-reffed components to the slots 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We're trying to detect if a ref is needed, but would it make sense to just forward it all the time?
In React 19 this isn't a problem because ref
is a normal prop. In React <= 18, the user will see a warning to add forwardRef
to the component if we're using a ref
.
The issue with this is that if we start passing a ref
to a component that uses consumeSlots
, the users in React <= 18 whose slot isn't wrapped in forwardRef
will start seeing a warning in dev. As long as behavior doesn't change with the lack of a ref, I don't think this is a breaking change, but it might be hard to detect that simply adding a ref
might cause warnings in end users using React <= 18.
I tested this in React 18 and the missing forwardRef
warning only shows up if we're actually using the ref. If we're forwarding it in consumeSlots
, but we're not using it, then it won't trigger a warning.
A warning would be triggered here in React <= 18 if the slot isn't wrapped in forwardRef
:
function Chart() {
const props = { /* Props without a ref */ }
const ref = useRef(null);
return <ChartsLegend {...props} ref={ref} />
}
A warning would not be triggered here in React <= 18 even if the slot isn't wrapped in forwardRef
:
function Chart() {
const props = { /* Props without a ref */ }
return <ChartsLegend {...props} />
}
If the slot is wrapped in forwardRef
or if in React >= 19, there would also be no warning.
Basically, the affected users would be someone on React <= 18, whose slot isn't wrapped in forwardRef
, and we add a ref
to a component that accepts slots. The consequence of this would be a warning in dev. Is this acceptable, @JCQuintas @alexfauquette?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was added in this breaking change window, so we can still change it without a BK.
I'm ok with always passing the ref. We can remove checking the function arguments length altogether.
|
||
if (process.env.NODE_ENV !== 'production') { | ||
OutComponent.displayName = `${name}.slots.${slotPropName}`; | ||
Component.displayName = `${name}.slots.${slotPropName}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, it is a good idea to change the displayName
of a user's component? Not sure if it's more confusing than helpful. I'm thinking of the use case of a user searching for their component in React DevTools and not being able to find it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The name change was mostly because of the ForwardRef which would wrap it into a new function, I just didn't check if a user component was passed.
Now we can probably remove it.
More info on the performance part: it's the logic we're running in I'm now trying to understand where the performance hit comes from and see if I can optimize |
Performance seems to be unchanged, so I'll revert those changes. |
28dc87c
to
a76f62c
Compare
Allow customizing shape in scatter charts by using the
marker
slot.This is my first time using slots, so I'm not sure if I'm using them properly and whether the
ownerState
/additionalProps
is well defined.Still need to write the docs, but at the moment I'm only looking for feedback on the implementation.