import * as React from 'react'; import { IStoreState } from '../index.data'; import { Provider } from 'unistore/react'; import { Store } from 'unistore'; import SpreadSheet from '../SpreadSheet'; import { validate, initStore, getCommands, getQueries } from './helper'; import { Props } from './index.data'; import ErrorBoundary from '../common/ErrorBoundery'; import RuntimeContext, { SpreadSheetRuntime } from '../RuntimeContext'; import NamedFormulaManager from '../formula-manager/NamedFormulaManager'; import PositionedFormulaManager from '../formula-manager/PositionedFormulaManager'; import { dissoc } from 'valor-app-utils'; import { rowNoTemplates } from '../constants'; import { getNormalizedState } from '../helper'; /** * 以后对外提供controller都在这里实现 */ class SpreadSheetProvider extends React.Component { store: Store; // commandManager: CommandManager; commands: ReturnType; queries: ReturnType; runtime: SpreadSheetRuntime; // 包含ij/rowNo的state getNormalizedState(shouldRecalculate: boolean = false) { shouldRecalculate && this.commands.recalculate(); return getNormalizedState(this.store.getState(), this.props.rowNoTemplates); } constructor(props: Props) { super(props); validate(props); const store = initStore(props); const formulaConfig = props.formulaConfig || { userFormula: 'byPosition' }; const formulaManager = props.formulaConfig && props.formulaConfig.userFormula === 'byName' ? new NamedFormulaManager(store, dissoc(formulaConfig, 'userFormula')) : new PositionedFormulaManager(store, dissoc(formulaConfig, 'userFormula')); this.runtime = new SpreadSheetRuntime( store, formulaManager, props.checkableConfig, props.rowNoTemplates || rowNoTemplates, false, !!this.props.disableAutoCalculate, ); this.store = store; // 供外部调用 this.commands = this.runtime.commands; this.queries = this.runtime.queries; this.getNormalizedState = this.getNormalizedState.bind(this); this.batchUpdate = this.batchUpdate.bind(this); this.notifySelectionChanged = this.notifySelectionChanged.bind(this); } /** * 非常重要! * 它确保了 外部组件不会刷新 SpreadSheetProvider, 从而避免了 错误地重新初始化store * 相关思考: https://github.com/g770728y/valor-blog/issues/11#issuecomment-572336775 **/ shouldComponentUpdate() { return false; } setDisableAutoCalculate(disableAutoCalculate: boolean) { if (disableAutoCalculate !== this.runtime.disableAutoCalculate) { this.runtime.disableAutoCalculate = disableAutoCalculate; if (!disableAutoCalculate) { this.commands.recalculate(); } } } batchUpdate(updateFn: () => void) { try { if (this.runtime.disableAutoCalculate) { this.runtime.batchMode = true; updateFn(); this.commands.recalculate(); } else { updateFn(); } } finally { this.runtime.batchMode = false; } } componentWillUnmount() { this.runtime.dispose(); this.store.unsubscribe(this.notifySelectionChanged); } componentDidMount() { this.store.subscribe(this.notifySelectionChanged); } notifySelectionChanged(state: IStoreState) { const { selectionType, selectedRowRange, selectedColumnRange, selectedCellRange } = state; this.props.onSelectionChanged && this.props.onSelectionChanged({ selectionType, selectedRowRange, selectedColumnRange, selectedCellRange, }); } render() { return ( ); } } export default SpreadSheetProvider;