@antv/s2-react
Version:
use S2 with react
145 lines • 6.8 kB
JavaScript
import { __awaiter } from "tslib";
import { PivotSheet, TableSheet } from '@antv/s2';
import { PivotChartSheet } from '@antv/s2/extends';
import { useUpdate, useUpdateEffect } from 'ahooks';
import { identity, isEqual } from 'lodash';
import React from 'react';
import { getSheetComponentOptions } from '../utils';
import { useEvents } from './useEvents';
import { useLoading } from './useLoading';
import { usePagination } from './usePagination';
import { useResize } from './useResize';
export function useSpreadSheet(props) {
const forceUpdate = useUpdate();
const s2Ref = React.useRef(null);
const containerRef = React.useRef(null);
const wrapperRef = React.useRef(null);
const shouldInit = React.useRef(true);
const isDevMode = React.useMemo(() => {
try {
return process.env['NODE_ENV'] !== 'production';
}
catch (_a) {
return false;
}
}, []);
const { spreadsheet: customSpreadSheet, dataCfg, options, themeCfg, sheetType, onUpdate = identity, onUpdateAfterRender, onLoading, } = props;
/** 保存重渲 effect 的 deps */
const updatePrevDepsRef = React.useRef([dataCfg, options, themeCfg]);
const { loading, setLoading } = useLoading(s2Ref.current, props.loading);
const pagination = usePagination(s2Ref.current, props.options);
useEvents(props, s2Ref.current);
const renderSpreadSheet = React.useCallback((container) => {
const s2Options = getSheetComponentOptions(options);
if (customSpreadSheet) {
return customSpreadSheet(container, dataCfg, s2Options);
}
if (sheetType === 'table') {
return new TableSheet(container, dataCfg, s2Options);
}
if (sheetType === 'pivotChart') {
return new PivotChartSheet(container, dataCfg, s2Options);
}
return new PivotSheet(container, dataCfg, s2Options);
}, [sheetType, options, dataCfg, customSpreadSheet]);
const buildSpreadSheet = React.useCallback(() => __awaiter(this, void 0, void 0, function* () {
var _a;
setLoading(true);
const s2 = renderSpreadSheet(containerRef.current);
s2.setThemeCfg(props.themeCfg);
yield s2.render();
setLoading(false);
s2Ref.current = s2;
/**
* 子 hooks 内使用了 s2Ref.current 作为 deps
* forceUpdate 一下保证子 hooks 能 rerender
*/
forceUpdate();
(_a = props.onMounted) === null || _a === void 0 ? void 0 : _a.call(props, s2Ref.current);
}), [props, renderSpreadSheet, setLoading, forceUpdate]);
// 适用于监听 loading 状态, 组件外部使用 <Spin /> 等场景
React.useEffect(() => {
onLoading === null || onLoading === void 0 ? void 0 : onLoading(loading);
}, [loading]);
React.useEffect(() => {
// 兼容 React 18 StrictMode 开发环境下渲染两次
if (isDevMode && !shouldInit.current) {
return;
}
buildSpreadSheet();
shouldInit.current = false;
return () => {
var _a, _b;
setLoading(false);
(_b = (_a = s2Ref.current) === null || _a === void 0 ? void 0 : _a.destroy) === null || _b === void 0 ? void 0 : _b.call(_a);
};
}, [isDevMode]);
// 重渲 effect:dataCfg, options or theme changed
useUpdateEffect(() => {
const render = () => __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
setLoading(true);
const [prevDataCfg, prevOptions, prevThemeCfg] = updatePrevDepsRef.current;
updatePrevDepsRef.current = [dataCfg, options, themeCfg];
let rerender = false;
let reloadData = false;
let rebuildDataSet = false;
if (!Object.is(prevDataCfg, dataCfg)) {
// 列头变化需要重新计算初始叶子节点
if (((_b = (_a = prevDataCfg === null || prevDataCfg === void 0 ? void 0 : prevDataCfg.fields) === null || _a === void 0 ? void 0 : _a.columns) === null || _b === void 0 ? void 0 : _b.length) !==
((_d = (_c = dataCfg === null || dataCfg === void 0 ? void 0 : dataCfg.fields) === null || _c === void 0 ? void 0 : _c.columns) === null || _d === void 0 ? void 0 : _d.length)) {
(_f = (_e = s2Ref.current) === null || _e === void 0 ? void 0 : _e.facet) === null || _f === void 0 ? void 0 : _f.clearInitColLeafNodes();
}
reloadData = true;
rerender = true;
(_g = s2Ref.current) === null || _g === void 0 ? void 0 : _g.setDataCfg(dataCfg);
}
if (!isEqual(prevOptions, options)) {
if ((prevOptions === null || prevOptions === void 0 ? void 0 : prevOptions.hierarchyType) !== (options === null || options === void 0 ? void 0 : options.hierarchyType)) {
rebuildDataSet = true;
reloadData = true;
(_h = s2Ref.current) === null || _h === void 0 ? void 0 : _h.setDataCfg(dataCfg);
}
rerender = true;
(_j = s2Ref.current) === null || _j === void 0 ? void 0 : _j.setOptions(options);
(_k = s2Ref.current) === null || _k === void 0 ? void 0 : _k.changeSheetSize(options.width, options.height);
}
if (!isEqual(prevThemeCfg, themeCfg)) {
rerender = true;
(_l = s2Ref.current) === null || _l === void 0 ? void 0 : _l.setThemeCfg(themeCfg);
}
if (!rerender) {
setLoading(false);
return;
}
/**
* onUpdate 交出控制权
* 由传入方决定最终的 render 模式
*/
const defaultRenderOptions = {
reloadData,
rebuildDataSet,
};
const renderOptions = (onUpdate === null || onUpdate === void 0 ? void 0 : onUpdate(defaultRenderOptions)) || defaultRenderOptions;
yield ((_m = s2Ref.current) === null || _m === void 0 ? void 0 : _m.render(renderOptions));
setLoading(false);
onUpdateAfterRender === null || onUpdateAfterRender === void 0 ? void 0 : onUpdateAfterRender(renderOptions);
});
render();
}, [dataCfg, options, themeCfg, onUpdate]);
useResize({
s2: s2Ref.current,
container: containerRef.current,
wrapper: wrapperRef.current,
adaptive: props.adaptive,
});
return {
s2Ref,
containerRef,
wrapperRef,
loading,
setLoading,
pagination,
};
}
//# sourceMappingURL=useSpreadSheet.js.map