Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,15 @@ export const useChartFunnelAxis: ChartPlugin<UseChartFunnelAxisSignature> = ({
return;
}

store.update((prev) => ({
...prev,
store.update({
funnel: {
gap: gap ?? 0,
},
cartesianAxis: {
...prev.cartesianAxis,
x: defaultizeXAxis(xAxis, dataset),
y: defaultizeYAxis(yAxis, dataset),
},
}));
});
}, [seriesConfig, drawingArea, xAxis, yAxis, dataset, store, gap]);

React.useEffect(() => {
Expand Down Expand Up @@ -129,9 +127,9 @@ export const useChartFunnelAxis: ChartPlugin<UseChartFunnelAxisSignature> = ({
}

const axisClickHandler = instance.addInteractionListener('tap', (event) => {
const { axis: xAxisWithScale, axisIds: xAxisIds } = selectorChartXAxis(store.value);
const { axis: yAxisWithScale, axisIds: yAxisIds } = selectorChartYAxis(store.value);
const processedSeries = selectorChartSeriesProcessed(store.value);
const { axis: xAxisWithScale, axisIds: xAxisIds } = selectorChartXAxis(store.state);
const { axis: yAxisWithScale, axisIds: yAxisIds } = selectorChartYAxis(store.state);
const processedSeries = selectorChartSeriesProcessed(store.state);

const usedXAxis = xAxisIds[0];
const usedYAxis = yAxisIds[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,14 @@ export const useSankeyHighlight: ChartPlugin<UseSankeyHighlightSignature> = ({ s
});

useEnhancedEffect(() => {
store.update((prevState) =>
prevState.highlight.item === params.highlightedItem
? prevState
: {
...prevState,
highlight: {
...prevState.highlight,
item: params.highlightedItem,
},
},
);
if (store.state.highlight.item !== params.highlightedItem) {
store.set('highlight', { ...store.state.highlight, item: params.highlightedItem });
}
}, [store, params.highlightedItem]);

const clearHighlight = useEventCallback(() => {
params.onHighlightChange?.(null);
store.update((prev) => ({ ...prev, highlight: { item: null } }));
store.set('highlight', { ...store.state.highlight, item: null });
});

const setHighlight = useEventCallback((newItem: SankeyHighlightItemData) => {
Expand All @@ -48,7 +40,7 @@ export const useSankeyHighlight: ChartPlugin<UseSankeyHighlightSignature> = ({ s
}

params.onHighlightChange?.(newItem);
store.update((prev) => ({ ...prev, highlight: { item: newItem } }));
store.set('highlight', { ...store.state.highlight, item: newItem });
});

return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const usePanOnDrag = (

const handlePanStart = (event: PanEvent) => {
if (!(event.detail.target as SVGElement)?.closest('[data-charts-zoom-slider]')) {
startRef.current = store.value.zoom.zoomData;
startRef.current = store.state.zoom.zoomData;
}
};
const handlePanEnd = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export const usePanOnPressAndDrag = (

const handlePressAndDragStart = (event: PressAndDragEvent) => {
if (!(event.detail.target as SVGElement)?.closest('[data-charts-zoom-slider]')) {
startRef.current = store.value.zoom.zoomData;
startRef.current = store.state.zoom.zoomData;
}
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,9 @@ export const useChartProZoom: ChartPlugin<UseChartProZoomSignature> = (pluginDat
const optionsLookup = useSelector(store, selectorChartZoomOptionsLookup);

useEffectAfterFirstRender(() => {
store.update((prevState) => {
return {
...prevState,
zoom: {
...prevState.zoom,
zoomInteractionConfig: initializeZoomInteractionConfig(zoomInteractionConfig),
},
};
store.set('zoom', {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to have a "partial set" where we only provide the changed props and the behaviour provides the unchanged ones?

@romgrk

// current
set<T>(key: keyof State, value: T) {
  if (!Object.is(this.state[key], value)) {
    this.setState({ ...this.state, [key]: value });
  }
}

// partial
partial<T>(key: keyof State, value: Partial<T>) {
  this.setState({ 
    ...this.state, 
    [key]: { ...this.state[key], ...value } 
  });
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense instead to implement support for nested keys? This would become store.set('zoom.zoomInteractionConfig', etc).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't that break the selectors? If the root object doesn't change how will siblings know that the parent updated? 🤔

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The implementation would mutate every parent object, just like it happens in your partial() example.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yeah we could do that 😅

Then I believe that API is better indeed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might still need to update more than one prop though, so partial could still be useful 🙃

...store.state.zoom,
zoomInteractionConfig: initializeZoomInteractionConfig(zoomInteractionConfig),
});
}, [store, zoomInteractionConfig]);

Expand All @@ -52,38 +47,28 @@ export const useChartProZoom: ChartPlugin<UseChartProZoomSignature> = (pluginDat
if (paramsZoomData === undefined) {
return undefined;
}
store.update((prevState) => {
if (process.env.NODE_ENV !== 'production' && !prevState.zoom.isControlled) {
console.error(
[
`MUI X Charts: A chart component is changing the \`zoomData\` from uncontrolled to controlled.`,
'Elements should not switch from uncontrolled to controlled (or vice versa).',
'Decide between using a controlled or uncontrolled for the lifetime of the component.',
"The nature of the state is determined during the first render. It's considered controlled if the value is not `undefined`.",
'More info: https://fb.me/react-controlled-components',
].join('\n'),
);
}

return {
...prevState,
zoom: {
...prevState.zoom,
isInteracting: true,
zoomData: paramsZoomData,
},
};
if (process.env.NODE_ENV !== 'production' && !store.state.zoom.isControlled) {
console.error(
[
`MUI X Charts: A chart component is changing the \`zoomData\` from uncontrolled to controlled.`,
'Elements should not switch from uncontrolled to controlled (or vice versa).',
'Decide between using a controlled or uncontrolled for the lifetime of the component.',
"The nature of the state is determined during the first render. It's considered controlled if the value is not `undefined`.",
'More info: https://fb.me/react-controlled-components',
].join('\n'),
);
}
store.set('zoom', {
...store.state.zoom,
isInteracting: true,
zoomData: paramsZoomData,
});

const timeout = setTimeout(() => {
store.update((prevState) => {
return {
...prevState,
zoom: {
...prevState.zoom,
isInteracting: false,
},
};
store.set('zoom', {
...store.state.zoom,
isInteracting: false,
});
}, 166);

Expand All @@ -97,14 +82,9 @@ export const useChartProZoom: ChartPlugin<UseChartProZoomSignature> = (pluginDat
() =>
debounce(
() =>
store.update((prevState) => {
return {
...prevState,
zoom: {
...prevState.zoom,
isInteracting: false,
},
};
store.set('zoom', {
...store.state.zoom,
isInteracting: false,
}),
166,
),
Expand All @@ -113,23 +93,17 @@ export const useChartProZoom: ChartPlugin<UseChartProZoomSignature> = (pluginDat

const setZoomDataCallback = React.useCallback(
(zoomData: ZoomData[] | ((prev: ZoomData[]) => ZoomData[])) => {
store.update((prevState) => {
const newZoomData =
typeof zoomData === 'function' ? zoomData([...prevState.zoom.zoomData]) : zoomData;
onZoomChange?.(newZoomData);
if (prevState.zoom.isControlled) {
return prevState;
}

removeIsInteracting();
return {
...prevState,
zoom: {
...prevState.zoom,
isInteracting: true,
zoomData: newZoomData,
},
};
const newZoomData =
typeof zoomData === 'function' ? zoomData([...store.state.zoom.zoomData]) : zoomData;
onZoomChange?.(newZoomData);
if (store.state.zoom.isControlled) {
return;
}
removeIsInteracting();
store.set('zoom', {
...store.state.zoom,
isInteracting: true,
zoomData: newZoomData,
});
},
[onZoomChange, store, removeIsInteracting],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import * as React from 'react';
import { Store } from '@mui/x-internals/store';
import type {
ChartAnyPluginSignature,
ChartInstance,
ChartPublicAPI,
ChartState,
ConvertSignaturesIntoPlugins,
MergeSignaturesProperty,
} from '../../internals/plugins/models';
import type { ChartStore } from '../../internals/plugins/utils/ChartStore';
import type { ChartCorePluginSignatures } from '../../internals/plugins/corePlugins';
import type { ChartSeriesConfig } from '../../internals/plugins/models/seriesConfig';
import type { UseChartBaseProps } from '../../internals/store/useCharts.types';
Expand All @@ -27,7 +28,7 @@ export type ChartContextValue<
/**
* The internal state of the chart.
*/
store: ChartStore<TSignatures>;
store: Store<ChartState<TSignatures, TOptionalSignatures>>;
/**
* The ref to the <svg />.
*/
Expand Down
3 changes: 2 additions & 1 deletion packages/x-charts/src/hooks/useItemHighlightedGetter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
selectorChartsIsFadedCallback,
selectorChartsIsHighlightedCallback,
} from '../internals/plugins/featurePlugins/useChartHighlight/useChartHighlight.selectors';
import { UseChartHighlightSignature } from '../plugins';

/**
* A hook to check the highlighted state of multiple items.
Expand All @@ -15,7 +16,7 @@ import {
* @returns {{ isHighlighted, isFaded }} callbacks to get the state of the item.
*/
export function useItemHighlightedGetter() {
const store = useStore();
const store = useStore<[UseChartHighlightSignature]>();

const isHighlighted = useSelector(store, selectorChartsIsHighlightedCallback);
const isFaded = useSelector(store, selectorChartsIsFadedCallback);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,16 @@ import type { UseChartAnimationSignature } from './useChartAnimation.types';

export const useChartAnimation: ChartPlugin<UseChartAnimationSignature> = ({ params, store }) => {
React.useEffect(() => {
store.update((prevState) => {
return {
...prevState,
animation: { ...prevState.animation, skip: params.skipAnimation },
};
});
store.set('animation', { ...store.state.animation, skip: params.skipAnimation });
}, [store, params.skipAnimation]);

const disableAnimation = React.useCallback(() => {
let disableCalled = false;

store.update((prevState) => ({
...prevState,
animation: {
...prevState.animation,
skipAnimationRequests: prevState.animation.skipAnimationRequests + 1,
},
}));
store.set('animation', {
...store.state.animation,
skipAnimationRequests: store.state.animation.skipAnimationRequests + 1,
});

return () => {
if (disableCalled) {
Expand All @@ -32,13 +24,10 @@ export const useChartAnimation: ChartPlugin<UseChartAnimationSignature> = ({ par

disableCalled = true;

store.update((prevState) => ({
...prevState,
animation: {
...prevState.animation,
skipAnimationRequests: prevState.animation.skipAnimationRequests - 1,
},
}));
store.set('animation', {
...store.state.animation,
skipAnimationRequests: store.state.animation.skipAnimationRequests - 1,
});
};
}, [store]);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
'use client';
import * as React from 'react';
import { useEffectAfterFirstRender } from '@mui/x-internals/useEffectAfterFirstRender';
import useEnhancedEffect from '@mui/utils/useEnhancedEffect';
import ownerWindow from '@mui/utils/ownerWindow';
import { useSelector } from '../../../store/useSelector';
Expand Down Expand Up @@ -35,27 +36,20 @@ export const useChartDimensions: ChartPlugin<UseChartDimensionsSignature> = ({
const newHeight = Math.floor(parseFloat(computedStyle.height)) || 0;
const newWidth = Math.floor(parseFloat(computedStyle.width)) || 0;

store.update((prev) => {
if (prev.dimensions.width === newWidth && prev.dimensions.height === newHeight) {
return prev;
}

return {
...prev,
dimensions: {
margin: {
top: params.margin.top,
right: params.margin.right,
bottom: params.margin.bottom,
left: params.margin.left,
},
width: params.width ?? newWidth,
height: params.height ?? newHeight,
propsWidth: params.width,
propsHeight: params.height,
if (store.state.dimensions.width !== newWidth || store.state.dimensions.height !== newHeight) {
store.set('dimensions', {
margin: {
top: params.margin.top,
right: params.margin.right,
bottom: params.margin.bottom,
left: params.margin.left,
},
};
});
width: params.width ?? newWidth,
height: params.height ?? newHeight,
propsWidth: params.width,
propsHeight: params.height,
});
}
return {
height: newHeight,
width: newWidth,
Expand All @@ -72,26 +66,20 @@ export const useChartDimensions: ChartPlugin<UseChartDimensionsSignature> = ({
params.margin.bottom,
]);

React.useEffect(() => {
store.update((prev) => {
const width = params.width ?? prev.dimensions.width;
const height = params.height ?? prev.dimensions.height;

return {
...prev,
dimensions: {
margin: {
top: params.margin.top,
right: params.margin.right,
bottom: params.margin.bottom,
left: params.margin.left,
},
width,
height,
propsHeight: params.height,
propsWidth: params.width,
},
};
useEffectAfterFirstRender(() => {
const width = params.width ?? store.state.dimensions.width;
const height = params.height ?? store.state.dimensions.height;
store.set('dimensions', {
margin: {
top: params.margin.top,
right: params.margin.right,
bottom: params.margin.bottom,
left: params.margin.left,
},
width,
height,
propsHeight: params.height,
propsWidth: params.width,
});
}, [
store,
Expand Down
Loading
Loading