From edefff5841f89e0d503c2b5492c806d3cb9570a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Tue, 27 Dec 2022 14:48:07 +0800 Subject: [PATCH] refactor: use @rc-component/context --- package.json | 1 + src/Body/BodyRow.tsx | 6 +- src/Body/ExpandedRow.tsx | 6 +- src/Body/index.tsx | 8 +- src/Cell/index.tsx | 6 +- src/ContextSelector/index.tsx | 113 ----------------------------- src/FixedHolder/index.tsx | 4 +- src/Footer/Cell.tsx | 4 +- src/Footer/index.tsx | 4 +- src/Header/Header.tsx | 4 +- src/Header/HeaderRow.tsx | 4 +- src/context/BodyContext.tsx | 2 +- src/context/ExpandedRowContext.tsx | 2 +- src/context/HoverContext.tsx | 2 +- src/context/ResizeContext.tsx | 2 +- src/context/TableContext.tsx | 2 +- src/stickyScrollBar.tsx | 4 +- tests/useContextSelector.spec.tsx | 36 --------- 18 files changed, 31 insertions(+), 179 deletions(-) delete mode 100644 src/ContextSelector/index.tsx delete mode 100644 tests/useContextSelector.spec.tsx diff --git a/package.json b/package.json index 25187e3da..ddeb2e522 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ }, "dependencies": { "@babel/runtime": "^7.10.1", + "@rc-component/context": "^1.0.0", "classnames": "^2.2.5", "rc-resize-observer": "^1.1.0", "rc-util": "^5.22.5", diff --git a/src/Body/BodyRow.tsx b/src/Body/BodyRow.tsx index af49a155c..fe3f27214 100644 --- a/src/Body/BodyRow.tsx +++ b/src/Body/BodyRow.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import Cell from '../Cell'; import BodyContext from '../context/BodyContext'; import TableContext from '../context/TableContext'; -import { useContextSelector } from '../ContextSelector'; +import { useContext } from '@rc-component/context'; import type { ColumnType, CustomizeComponent, @@ -52,7 +52,7 @@ function BodyRow( scopeCellComponent, childrenColumnName, } = props; - const { prefixCls, fixedInfoList } = useContextSelector(TableContext, [ + const { prefixCls, fixedInfoList } = useContext(TableContext, [ 'prefixCls', 'fixedInfoList', ]); @@ -67,7 +67,7 @@ function BodyRow( expandIcon, expandedRowRender, expandIconColumnIndex, - } = useContextSelector(BodyContext, [ + } = useContext(BodyContext, [ 'flattenColumns', 'expandableType', 'expandRowByClick', diff --git a/src/Body/ExpandedRow.tsx b/src/Body/ExpandedRow.tsx index b4ad34f72..c20be0c0d 100644 --- a/src/Body/ExpandedRow.tsx +++ b/src/Body/ExpandedRow.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import Cell from '../Cell'; import ExpandedRowContext from '../context/ExpandedRowContext'; import TableContext from '../context/TableContext'; -import { useContextSelector } from '../ContextSelector'; +import { useContext } from '@rc-component/context'; import type { CustomizeComponent } from '../interface'; export interface ExpandedRowProps { @@ -26,8 +26,8 @@ function ExpandedRow({ colSpan, isEmpty, }: ExpandedRowProps) { - const scrollbarSize = useContextSelector(TableContext, 'scrollbarSize'); - const { fixHeader, fixColumn, componentWidth, horizonScroll } = useContextSelector( + const scrollbarSize = useContext(TableContext, 'scrollbarSize'); + const { fixHeader, fixColumn, componentWidth, horizonScroll } = useContext( ExpandedRowContext, ['fixHeader', 'fixColumn', 'componentWidth', 'horizonScroll'], ); diff --git a/src/Body/index.tsx b/src/Body/index.tsx index c7f544dd1..0e448be7d 100644 --- a/src/Body/index.tsx +++ b/src/Body/index.tsx @@ -5,7 +5,7 @@ import type { PerfRecord } from '../context/PerfContext'; import PerfContext from '../context/PerfContext'; import ResizeContext from '../context/ResizeContext'; import TableContext from '../context/TableContext'; -import { useContextSelector } from '../ContextSelector'; +import { useContext } from '@rc-component/context'; import useFlattenRecords from '../hooks/useFlattenRecords'; import type { GetComponentProps, GetRowKey, Key } from '../interface'; import { getColumnsKey } from '../utils/valueUtil'; @@ -34,12 +34,12 @@ function Body({ emptyNode, childrenColumnName, }: BodyProps) { - const onColumnResize = useContextSelector(ResizeContext, 'onColumnResize'); - const { prefixCls, getComponent } = useContextSelector(TableContext, [ + const onColumnResize = useContext(ResizeContext, 'onColumnResize'); + const { prefixCls, getComponent } = useContext(TableContext, [ 'prefixCls', 'getComponent', ]); - const flattenColumns = useContextSelector(BodyContext, 'flattenColumns'); + const flattenColumns = useContext(BodyContext, 'flattenColumns'); const flattenData: { record: RecordType; indent: number; index: number }[] = useFlattenRecords(data, childrenColumnName, expandedKeys, getRowKey); diff --git a/src/Cell/index.tsx b/src/Cell/index.tsx index b81fa63f9..4d57c3b7f 100644 --- a/src/Cell/index.tsx +++ b/src/Cell/index.tsx @@ -8,7 +8,7 @@ import type { HoverContextProps } from '../context/HoverContext'; import HoverContext from '../context/HoverContext'; import PerfContext from '../context/PerfContext'; import StickyContext from '../context/StickyContext'; -import { useContextSelector } from '../ContextSelector'; +import { useContext } from '@rc-component/context'; import type { AlignType, CellEllipsisType, @@ -146,7 +146,7 @@ function Cell( const perfRecord = React.useContext(PerfContext); const supportSticky = React.useContext(StickyContext); - const allColumnsFixedLeft = useContextSelector(BodyContext, 'allColumnsFixedLeft'); + const allColumnsFixedLeft = useContext(BodyContext, 'allColumnsFixedLeft'); // ==================== Child Node ==================== const [childNode, legacyCellProps] = React.useMemo< @@ -342,7 +342,7 @@ const WrappedCell = React.forwardRef((props: CellProps, ref: React.Ref const mergedColSpan = colSpan ?? cellColSpan; const mergedRowSpan = rowSpan ?? cellRowSpan; - const { onHover, hovering } = useContextSelector(HoverContext, cxt => { + const { onHover, hovering } = useContext(HoverContext, cxt => { const isHovering = inHoverRange(index, mergedRowSpan || 1, cxt?.startRow, cxt?.endRow); return { diff --git a/src/ContextSelector/index.tsx b/src/ContextSelector/index.tsx deleted file mode 100644 index 227e8b1b9..000000000 --- a/src/ContextSelector/index.tsx +++ /dev/null @@ -1,113 +0,0 @@ -import useEvent from 'rc-util/lib/hooks/useEvent'; -import useLayoutEffect from 'rc-util/lib/hooks/useLayoutEffect'; -import * as React from 'react'; -import { unstable_batchedUpdates } from 'react-dom'; -import shallowEqual from 'shallowequal'; - -export type Selector = (value: T) => O; - -export type Trigger = (value: T) => void; - -export type Listeners = Set>; - -export interface Context { - getValue: () => T; - listeners: Listeners; -} - -export interface ContextSelectorProviderProps { - value: T; - children?: React.ReactNode; -} - -export interface ReturnCreateContext { - Context: React.Context>; - Provider: React.ComponentType>; -} - -export function createContext(defaultContext?: T): ReturnCreateContext { - const Context = React.createContext>(defaultContext as any); - - const Provider = ({ value, children }: ContextSelectorProviderProps) => { - const valueRef = React.useRef(value); - valueRef.current = value; - - const [context] = React.useState>(() => ({ - getValue: () => valueRef.current, - listeners: new Set(), - })); - - useLayoutEffect(() => { - unstable_batchedUpdates(() => { - context.listeners.forEach(listener => { - listener(value); - }); - }); - }, [value]); - - return {children}; - }; - - return { Context, Provider }; -} - -export function useContextSelector( - holder: ReturnCreateContext, - selector: Selector, -): O; -export function useContextSelector>( - holder: ReturnCreateContext, - selector: (keyof T)[], -): O; -export function useContextSelector( - holder: ReturnCreateContext, - selector: S, -): T[S]; - -export function useContextSelector( - holder: ReturnCreateContext, - selector: Selector | (keyof T)[] | keyof T, -) { - const eventSelector = useEvent>( - typeof selector === 'function' - ? selector - : ctx => { - if (!Array.isArray(selector)) { - return ctx[selector]; - } - - const obj = {} as O; - selector.forEach(key => { - (obj as any)[key] = ctx[key]; - }); - return obj; - }, - ); - const context = React.useContext(holder?.Context); - const { listeners, getValue } = context || {}; - - const valueRef = React.useRef(); - valueRef.current = eventSelector(context ? getValue() : null); - const [, forceUpdate] = React.useState({}); - - useLayoutEffect(() => { - if (!context) { - return; - } - - function trigger(nextValue: T) { - const nextSelectorValue = eventSelector(nextValue); - if (!shallowEqual(valueRef.current, nextSelectorValue)) { - forceUpdate({}); - } - } - - listeners.add(trigger); - - return () => { - listeners.delete(trigger); - }; - }, [context]); - - return valueRef.current; -} diff --git a/src/FixedHolder/index.tsx b/src/FixedHolder/index.tsx index 8825c9d51..565c1ae29 100644 --- a/src/FixedHolder/index.tsx +++ b/src/FixedHolder/index.tsx @@ -4,7 +4,7 @@ import * as React from 'react'; import { useMemo } from 'react'; import ColGroup from '../ColGroup'; import TableContext from '../context/TableContext'; -import { useContextSelector } from '../ContextSelector'; +import { useContext } from '@rc-component/context'; import type { HeaderProps } from '../Header/Header'; import type { ColumnsType, ColumnType } from '../interface'; @@ -60,7 +60,7 @@ const FixedHolder = React.forwardRef>( }, ref, ) => { - const { prefixCls, scrollbarSize, isSticky } = useContextSelector(TableContext, [ + const { prefixCls, scrollbarSize, isSticky } = useContext(TableContext, [ 'prefixCls', 'scrollbarSize', 'isSticky', diff --git a/src/Footer/Cell.tsx b/src/Footer/Cell.tsx index 53f3e8a66..2ecbd407a 100644 --- a/src/Footer/Cell.tsx +++ b/src/Footer/Cell.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import Cell from '../Cell'; import TableContext from '../context/TableContext'; -import { useContextSelector } from '../ContextSelector'; +import { useContext } from '@rc-component/context'; import type { AlignType } from '../interface'; import { getCellFixedInfo } from '../utils/fixUtil'; import SummaryContext from './SummaryContext'; @@ -23,7 +23,7 @@ export default function SummaryCell({ rowSpan, align, }: SummaryCellProps) { - const { prefixCls, direction } = useContextSelector(TableContext, ['prefixCls', 'direction']); + const { prefixCls, direction } = useContext(TableContext, ['prefixCls', 'direction']); const { scrollColumnIndex, stickyOffsets, flattenColumns } = React.useContext(SummaryContext); const lastIndex = index + colSpan - 1; const mergedColSpan = lastIndex + 1 === scrollColumnIndex ? colSpan + 1 : colSpan; diff --git a/src/Footer/index.tsx b/src/Footer/index.tsx index 4f10d2d2c..3dd7e21d7 100644 --- a/src/Footer/index.tsx +++ b/src/Footer/index.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import TableContext from '../context/TableContext'; -import { useContextSelector } from '../ContextSelector'; +import { useContext } from '@rc-component/context'; import type { ColumnType, StickyOffsets } from '../interface'; import Summary from './Summary'; import SummaryContext from './SummaryContext'; @@ -14,7 +14,7 @@ export interface FooterProps { } function Footer({ children, stickyOffsets, flattenColumns }: FooterProps) { - const prefixCls = useContextSelector(TableContext, 'prefixCls'); + const prefixCls = useContext(TableContext, 'prefixCls'); const lastColumnIndex = flattenColumns.length - 1; const scrollColumn = flattenColumns[lastColumnIndex]; diff --git a/src/Header/Header.tsx b/src/Header/Header.tsx index dd4b2f6aa..7820bec14 100644 --- a/src/Header/Header.tsx +++ b/src/Header/Header.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import TableContext from '../context/TableContext'; -import { useContextSelector } from '../ContextSelector'; +import { useContext } from '@rc-component/context'; import type { CellType, ColumnGroupType, @@ -95,7 +95,7 @@ function Header({ flattenColumns, onHeaderRow, }: HeaderProps): React.ReactElement { - const { prefixCls, getComponent } = useContextSelector(TableContext, [ + const { prefixCls, getComponent } = useContext(TableContext, [ 'prefixCls', 'getComponent', ]); diff --git a/src/Header/HeaderRow.tsx b/src/Header/HeaderRow.tsx index 5e6a03122..c6db6d7e0 100644 --- a/src/Header/HeaderRow.tsx +++ b/src/Header/HeaderRow.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import Cell from '../Cell'; import TableContext from '../context/TableContext'; -import { useContextSelector } from '../ContextSelector'; +import { useContext } from '@rc-component/context'; import type { CellType, ColumnType, @@ -33,7 +33,7 @@ function HeaderRow({ onHeaderRow, index, }: RowProps) { - const { prefixCls, direction } = useContextSelector(TableContext, ['prefixCls', 'direction']); + const { prefixCls, direction } = useContext(TableContext, ['prefixCls', 'direction']); let rowProps: React.HTMLAttributes; if (onHeaderRow) { diff --git a/src/context/BodyContext.tsx b/src/context/BodyContext.tsx index f43754f31..166add7dc 100644 --- a/src/context/BodyContext.tsx +++ b/src/context/BodyContext.tsx @@ -1,4 +1,4 @@ -import { createContext } from '../ContextSelector'; +import { createContext } from '@rc-component/context'; import type { ColumnsType, ColumnType, diff --git a/src/context/ExpandedRowContext.tsx b/src/context/ExpandedRowContext.tsx index b2e17a497..39b91e420 100644 --- a/src/context/ExpandedRowContext.tsx +++ b/src/context/ExpandedRowContext.tsx @@ -1,4 +1,4 @@ -import { createContext } from '../ContextSelector'; +import { createContext } from '@rc-component/context'; export interface ExpandedRowProps { componentWidth: number; diff --git a/src/context/HoverContext.tsx b/src/context/HoverContext.tsx index e5239ed55..2d7d3665e 100644 --- a/src/context/HoverContext.tsx +++ b/src/context/HoverContext.tsx @@ -1,4 +1,4 @@ -import { createContext } from '../ContextSelector'; +import { createContext } from '@rc-component/context'; export interface HoverContextProps { startRow: number; diff --git a/src/context/ResizeContext.tsx b/src/context/ResizeContext.tsx index 536292e6b..d5880789c 100644 --- a/src/context/ResizeContext.tsx +++ b/src/context/ResizeContext.tsx @@ -1,5 +1,5 @@ import type * as React from 'react'; -import { createContext } from '../ContextSelector'; +import { createContext } from '@rc-component/context'; interface ResizeContextProps { onColumnResize: (columnKey: React.Key, width: number) => void; diff --git a/src/context/TableContext.tsx b/src/context/TableContext.tsx index 121f3e227..69acb2765 100644 --- a/src/context/TableContext.tsx +++ b/src/context/TableContext.tsx @@ -1,4 +1,4 @@ -import { createContext } from '../ContextSelector'; +import { createContext } from '@rc-component/context'; import type { GetComponent } from '../interface'; import type { FixedInfo } from '../utils/fixUtil'; diff --git a/src/stickyScrollBar.tsx b/src/stickyScrollBar.tsx index 437ac26ab..712878283 100644 --- a/src/stickyScrollBar.tsx +++ b/src/stickyScrollBar.tsx @@ -4,7 +4,7 @@ import { getOffset } from 'rc-util/lib/Dom/css'; import getScrollBarSize from 'rc-util/lib/getScrollBarSize'; import * as React from 'react'; import TableContext from './context/TableContext'; -import { useContextSelector } from './ContextSelector'; +import { useContext } from '@rc-component/context'; import { useLayoutState } from './hooks/useFrame'; interface StickyScrollBarProps { @@ -18,7 +18,7 @@ const StickyScrollBar: React.ForwardRefRenderFunction { - const prefixCls = useContextSelector(TableContext, 'prefixCls'); + const prefixCls = useContext(TableContext, 'prefixCls'); const bodyScrollWidth = scrollBodyRef.current?.scrollWidth || 0; const bodyWidth = scrollBodyRef.current?.clientWidth || 0; const scrollBarWidth = bodyScrollWidth && bodyWidth * (bodyWidth / bodyScrollWidth); diff --git a/tests/useContextSelector.spec.tsx b/tests/useContextSelector.spec.tsx deleted file mode 100644 index 62955a17f..000000000 --- a/tests/useContextSelector.spec.tsx +++ /dev/null @@ -1,36 +0,0 @@ -import { mount } from 'enzyme'; -import { createContext, useContextSelector } from '../src/ContextSelector'; - -describe('Table.useContextSelector', () => { - it('one render', () => { - let renderTimes = 0; - const Context = createContext(); - - const Sub = ({ children }: { children?: React.ReactNode }) => { - useContextSelector(Context, value => value); - return <>{children}; - }; - - const Final = () => { - renderTimes += 1; - return <>{useContextSelector(Context, value => value)}; - }; - - const Demo = ({ num }: { num: number }) => { - return ( - - - - - - ); - }; - - const wrapper = mount(); - expect(renderTimes).toEqual(1); - - // Rerender should only render once - wrapper.setProps({ num: 1 }); - expect(renderTimes).toEqual(2); - }); -});