-
-
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] Let the useXxxSeries
support array of ids and document them
#15545
Conversation
Deploy preview: https://deploy-preview-15545--material-ui-x.netlify.app/ |
CodSpeed Performance ReportMerging #15545 will not alter performanceComparing Summary
|
I'm wondering if the current hook is the best DX. If we provide something like useBarSeries(['seriesId1', 'seriesId2']) // Returns the config of the series
useBarSeries() // Returns all bar series in the correct order It might be easier to use |
Do you see a lot of value in returning an array for allowing multiple items to be returned or only allow one return per call? const a = useSeries('a')
const b = useSeries('b')
vs
const [a,b] useSeries('a', 'b') |
The array has the advantage to be easier to understand and to allow adding extra arguments later. But I'm not sure if passing an array like Maybe we should wait for the end of the plugin migration to see if one DX allows easier perf otpimisation than the other |
Optimisation-wise we can just |
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
Cherry-picked from mui#15545
Cherry-picked from mui#15545
Cherry-picked from mui#15545
Cherry-picked from mui#15545
Cherry-picked from mui#15545
6d2192a
to
7a70ef4
Compare
useSeries
and useXxxSeries
hookshooks
and improve types
|
||
/** | ||
* Get all the X axes. |
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 think that's how we standardize the docs naming for x/y axes
* Get all the X axes. | |
* Get all the x-axes. |
export function useSeriesOfType<T extends keyof ChartsSeriesConfig>( | ||
seriesType: T, | ||
...seriesIds: SeriesId[] | ||
) { | ||
const series = useSeries(); | ||
|
||
return React.useMemo( | ||
() => { | ||
if (seriesIds.length === 0) { | ||
return series[seriesType]; | ||
} | ||
|
||
if (seriesIds.length === 1) { | ||
return series?.[seriesType]?.series[seriesIds[0]]; | ||
} | ||
|
||
return seriesIds.map((id) => series?.[seriesType]?.series[id]).filter(Boolean); | ||
}, | ||
// DANGER: Ensure that the dependencies array is correct. | ||
// eslint-disable-next-line react-compiler/react-compiler | ||
// eslint-disable-next-line react-hooks/exhaustive-deps | ||
[series[seriesType], ...seriesIds], | ||
); | ||
} |
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.
Did you consider using selectors directly for the meoization?
export const selectorScatterSeries = createSelector(
[selectorChartSeriesProcessed],
(series) => series.scatter)
);
export const selectorScatterSeriesWithIds = createSelector(
[
selectorScatterSeries,
(_, ids: SeriesId | SeriesId[]
],
(scatterSeries, ids) => {
if(typeof ids === 'object'){
return ids.map(id => scatterSeries.series[id] ?? null)
}
return scatterSeries.series[ids] ?? null
}
);
Then
useScatterSeries(ids?: SeriesId | SeriesId[]){
const store = useStore()
return useSelector(store, ids===undefined ? selectorScatterSeries : selectorScatterSeriesWithIds, ids);
}
As long as the ids
stay the same, you should benefit from selector memoization
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.
It was quite hard to create a place where I could mock the return values, so in the end I'm testing them with the real chart components 😓
hooks
and improve typesuseXxxSeries
support array of ids and document them
I've allowed my self to update your PR title |
Good, because it said |
import { useStore } from './store/useStore'; | ||
import { useSelector } from './store/useSelector'; | ||
|
||
export function createSeriesSelectorsOfType<T extends keyof ChartsSeriesConfig>(seriesType: T) { |
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.
@alexfauquette tried to simplify the logic and keep it in a single place, so we can use createSeriesSelectorsOfType('pie')
, etc on the actual hooks.
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'm not 100% sure, but your idea is to call something like
useScatterSeries('id1', 'id2')
But then the following lines will transform 'id1', 'id2'
into ['id1', 'id2']
and so generate a new array which break the memoization.
export function useScatterSeries(...seriesIds: SeriesId[]): any {
return selectorSeries(seriesIds);
}
For me the only way to let user (or react compiler) memorize the ids is to pass directly an array
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
/** | ||
* Get access to the internal state of bar series. | ||
* The returned object contains: | ||
* - series: a mapping from ids to series attributes. | ||
* - seriesOrder: the array of series ids. | ||
* @returns {{ series: Record<SeriesId, DefaultizedBarSeriesType>; seriesOrder: SeriesId[]; } | undefined} barSeries | ||
*/ | ||
export function useBarSeries(): ProcessedSeries['bar']; | ||
/** | ||
* Get access to the internal state of bar series. | ||
* | ||
* @param {SeriesId} seriesId The id of the series to get. | ||
* @returns {ChartSeriesDefaultized<'bar'> | undefined} barSeries | ||
*/ | ||
export function useBarSeries(seriesId: SeriesId): ChartSeriesDefaultized<'bar'> | undefined; | ||
/** | ||
* Get access to the internal state of bar series. | ||
* | ||
* @param {SeriesId[]} seriesIds The ids of the series to get. Order is preserved. | ||
* @returns {ChartSeriesDefaultized<'bar'>[] | undefined} barSeries | ||
*/ | ||
export function useBarSeries( | ||
...seriesIds: SeriesId[] | ||
): (ChartSeriesDefaultized<'bar'> | undefined)[]; | ||
export function useBarSeries(...seriesIds: SeriesId[]): any { | ||
return selectorSeries(seriesIds); | ||
} |
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.
Should we divide the logic for useAllScatterSeries/useScatterSeriesAll
from the rest? The return values are wildly different 🤔
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 would add it to another PR though 😅
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 agree. Finding a good name for this hook is the main difficulty. Maybe useScatterSeriesContext
or useScatterSeriesState
even if it does not exactly translate what it is
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.
🎉
useXxxSeries
hooks and add more use-cases