Skip to content

Commit

Permalink
chore: Reusable pub-sub store util
Browse files Browse the repository at this point in the history
  • Loading branch information
pan-kot committed Nov 25, 2024
1 parent c59e8fd commit e0a8138
Show file tree
Hide file tree
Showing 15 changed files with 198 additions and 188 deletions.
7 changes: 3 additions & 4 deletions src/area-chart/__tests__/area-chart-use-chart-model.test.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { useImperativeHandle, useRef, useState } from 'react';
import React, { useImperativeHandle, useLayoutEffect, useRef, useState } from 'react';
import { fireEvent, render } from '@testing-library/react';

import { ElementWrapper } from '@cloudscape-design/test-utils-core/dom';
import { KeyCode } from '@cloudscape-design/test-utils-core/utils';

import { useReaction } from '../../../lib/components/area-chart/async-store';
import { AreaChartProps } from '../../../lib/components/area-chart/interfaces';
import { ChartModel } from '../../../lib/components/area-chart/model';
import useChartModel, { UseChartModelProps } from '../../../lib/components/area-chart/model/use-chart-model';
Expand Down Expand Up @@ -60,8 +59,8 @@ function RenderChartModelHook(props: UseChartModelProps<ChartDataTypes>) {
popoverRef,
});

useReaction(interactions, state => state.highlightedPoint, setHighlightedPoint);
useReaction(interactions, state => state.highlightedX, setHighlightedX);
useLayoutEffect(() => interactions.subscribe(s => s.highlightedPoint, setHighlightedPoint), [interactions]);
useLayoutEffect(() => interactions.subscribe(s => s.highlightedX, setHighlightedX), [interactions]);

useImperativeHandle(refs.plot, () => ({
svg: svgRef.current!,
Expand Down
78 changes: 0 additions & 78 deletions src/area-chart/async-store/__tests__/async-store.test.ts

This file was deleted.

90 changes: 0 additions & 90 deletions src/area-chart/async-store/index.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/area-chart/chart-container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import InlineStartLabels from '../internal/components/cartesian-chart/inline-sta
import LabelsMeasure from '../internal/components/cartesian-chart/labels-measure';
import ChartPlot from '../internal/components/chart-plot';
import { useMergeRefs } from '../internal/hooks/use-merge-refs';
import { useSelector } from '../internal/utils/async-store';
import useContainerWidth from '../internal/utils/use-container-width';
import { useSelector } from './async-store';
import AreaChartPopover from './elements/chart-popover';
import AreaDataSeries from './elements/data-series';
import AreaHighlightedPoint from './elements/highlighted-point';
Expand Down
2 changes: 1 addition & 1 deletion src/area-chart/elements/area-chart-legend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import React, { memo, useMemo } from 'react';

import ChartLegend from '../../internal/components/chart-legend';
import { useSelector } from '../async-store';
import { useSelector } from '../../internal/utils/async-store';
import { AreaChartProps } from '../interfaces';
import { ChartModel } from '../model';

Expand Down
2 changes: 1 addition & 1 deletion src/area-chart/elements/data-series.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, { memo } from 'react';
import clsx from 'clsx';

import { useUniqueId } from '../../internal/hooks/use-unique-id';
import { useSelector } from '../async-store';
import { useSelector } from '../../internal/utils/async-store';
import { AreaChartProps } from '../interfaces';
import { ChartModel } from '../model';
import AreaSeries from './area-series';
Expand Down
2 changes: 1 addition & 1 deletion src/area-chart/elements/highlighted-point.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import React, { forwardRef, memo } from 'react';

import HighlightedPoint from '../../internal/components/cartesian-chart/highlighted-point';
import { useSelector } from '../async-store';
import { useSelector } from '../../internal/utils/async-store';
import { ChartModel } from '../model';

export default memo(forwardRef(AreaHighlightedPoint));
Expand Down
2 changes: 1 addition & 1 deletion src/area-chart/elements/use-highlight-details.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { useInternalI18n } from '../../i18n/context';
import { CartesianChartProps } from '../../internal/components/cartesian-chart/interfaces';
import { ChartSeriesDetailItem } from '../../internal/components/chart-series-details';
import { useSelector } from '../async-store';
import { useSelector } from '../../internal/utils/async-store';
import { AreaChartProps } from '../interfaces';
import { ChartModel } from '../model';

Expand Down
2 changes: 1 addition & 1 deletion src/area-chart/elements/vertical-marker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import React, { memo } from 'react';

import VerticalMarker from '../../internal/components/cartesian-chart/vertical-marker';
import { useSelector } from '../async-store';
import { useSelector } from '../../internal/utils/async-store';
import { AreaChartProps } from '../interfaces';
import { ChartModel } from '../model';

Expand Down
2 changes: 1 addition & 1 deletion src/area-chart/model/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { XDomain, YDomain } from '../../internal/components/cartesian-chart/inte
import { ChartScale, NumericChartScale } from '../../internal/components/cartesian-chart/scales';
import { ChartPlotRef } from '../../internal/components/chart-plot';
import { ChartSeriesMarkerType } from '../../internal/components/chart-series-marker';
import { ReadonlyAsyncStore } from '../async-store';
import { ReadonlyAsyncStore } from '../../internal/utils/async-store';
import { AreaChartProps } from '../interfaces';

export interface ChartModel<T extends AreaChartProps.DataTypes> {
Expand Down
2 changes: 1 addition & 1 deletion src/area-chart/model/interactions-store.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import AsyncStore from '../async-store';
import AsyncStore from '../../internal/utils/async-store';
import { AreaChartProps } from '../interfaces';
import { ChartModel } from './index';

Expand Down
9 changes: 6 additions & 3 deletions src/area-chart/model/use-chart-model.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React, { MouseEvent, RefObject, useEffect, useMemo, useRef } from 'react';
import React, { MouseEvent, RefObject, useEffect, useLayoutEffect, useMemo, useRef } from 'react';

import { nodeContains } from '@cloudscape-design/component-toolkit/dom';
import { useStableCallback } from '@cloudscape-design/component-toolkit/internal';
Expand All @@ -13,7 +13,6 @@ import { circleIndex } from '../../internal/utils/circle-index';
import handleKey from '../../internal/utils/handle-key';
import { nodeBelongs } from '../../internal/utils/node-belongs';
import { throttle } from '../../internal/utils/throttle';
import { useReaction } from '../async-store';
import { AreaChartProps } from '../interfaces';
import computeChartProps from './compute-chart-props';
import createSeriesDecorator from './create-series-decorator';
Expand Down Expand Up @@ -373,7 +372,11 @@ export default function useChartModel<T extends AreaChartProps.DataTypes>({
]);

// Notify client when series highlight change.
useReaction(model.interactions, state => state.highlightedSeries, setHighlightedSeries);
setHighlightedSeries = useStableCallback(setHighlightedSeries);
useLayoutEffect(
() => model.interactions.subscribe(state => state.highlightedSeries, setHighlightedSeries),
[model.interactions, setHighlightedSeries]
);

// Update interactions store when series highlight in a controlled way.
useEffect(() => {
Expand Down
70 changes: 70 additions & 0 deletions src/internal/utils/__tests__/async-store.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import { act, renderHook } from '../../../__tests__/render-hook';
import AsyncStore, { useSelector } from '../async-store';

describe('AsyncStore', () => {
test('subscribers are notified when selected state is updated', () => {
const store = new AsyncStore({ west: 1, east: 2 });

let west = store.get().west;
store.subscribe(
state => state.west,
nextWest => {
west += nextWest;
}
);

let east = store.get().east * 2;
store.subscribe(
state => state.east,
nextEast => {
east += nextEast * 2;
}
);

store.set(state => ({ ...state, west: state.west + 1 }));
store.set(state => ({ ...state, east: state.east + 1 }));
store.set(state => ({ ...state, west: state.west + 1 }));

expect(store.get().west).toBe(3);
expect(west).toBe(1 + 2 + 3);

expect(store.get().east).toBe(3);
expect(east).toBe(4 + 6);
});

test('subscribers can unsubscribe from updates', () => {
const store = new AsyncStore({ west: 1, east: 2 });

let west = store.get().west;
const unsubscribeWest = store.subscribe(
state => state.west,
nextWest => {
west = nextWest;
}
);

store.set(state => ({ ...state, west: state.west + 1 }));
unsubscribeWest();
store.set(state => ({ ...state, west: state.west + 1 }));

expect(store.get().west).toBe(3);
expect(west).toBe(2);
});
});

describe('useSelector', () => {
test('selected state updates cause subscribed component to re-render', () => {
const store = new AsyncStore({ west: 1, east: 2 });

const { result } = renderHook(() => useSelector(store, s => s.west));
expect(result.current).toEqual(1);

act(() => store.set(state => ({ ...state, west: state.west + 1 })));
expect(result.current).toEqual(2);

act(() => store.set(state => ({ ...state, west: state.west + 1 })));
expect(result.current).toEqual(3);
});
});
Loading

0 comments on commit e0a8138

Please sign in to comment.