-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
/
Copy pathuseGridStateInitialization.ts
140 lines (118 loc) · 4.84 KB
/
useGridStateInitialization.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
import * as React from 'react';
import { DataGridProcessedProps } from '../../models/props/DataGridProps';
import type { GridPrivateApiCommon } from '../../models/api/gridApiCommon';
import { GridStateApi, GridStatePrivateApi } from '../../models/api/gridStateApi';
import { GridControlStateItem } from '../../models/controlStateItem';
import { GridSignature } from '../utils/useGridApiEventHandler';
import { useGridApiMethod } from '../utils';
import { isFunction } from '../../utils/utils';
export const useGridStateInitialization = <PrivateApi extends GridPrivateApiCommon>(
apiRef: React.MutableRefObject<PrivateApi>,
props: Pick<DataGridProcessedProps, 'signature'>,
) => {
const controlStateMapRef = React.useRef<
Record<string, GridControlStateItem<PrivateApi['state'], any>>
>({});
const [, rawForceUpdate] = React.useState<PrivateApi['state']>();
const registerControlState = React.useCallback<
GridStatePrivateApi<PrivateApi['state']>['registerControlState']
>((controlStateItem) => {
const { stateId, ...others } = controlStateItem;
controlStateMapRef.current[stateId] = {
...others,
stateId,
};
}, []);
const setState = React.useCallback<GridStateApi<PrivateApi['state']>['setState']>(
(state, reason) => {
let newState: PrivateApi['state'];
if (isFunction(state)) {
newState = state(apiRef.current.state);
} else {
newState = state;
}
if (apiRef.current.state === newState) {
return false;
}
let ignoreSetState = false;
// Apply the control state constraints
const updatedControlStateIds: { stateId: string; hasPropChanged: boolean }[] = [];
Object.keys(controlStateMapRef.current).forEach((stateId) => {
const controlState = controlStateMapRef.current[stateId];
const oldSubState = controlState.stateSelector(
apiRef.current.state,
apiRef.current.instanceId,
);
const newSubState = controlState.stateSelector(newState, apiRef.current.instanceId);
if (newSubState === oldSubState) {
return;
}
updatedControlStateIds.push({
stateId: controlState.stateId,
hasPropChanged: newSubState !== controlState.propModel,
});
// The state is controlled, the prop should always win
if (controlState.propModel !== undefined && newSubState !== controlState.propModel) {
ignoreSetState = true;
}
});
if (updatedControlStateIds.length > 1) {
// Each hook modify its own state, and it should not leak
// Events are here to forward to other hooks and apply changes.
// You are trying to update several states in a no isolated way.
throw new Error(
`You're not allowed to update several sub-state in one transaction. You already updated ${
updatedControlStateIds[0].stateId
}, therefore, you're not allowed to update ${updatedControlStateIds
.map((el) => el.stateId)
.join(', ')} in the same transaction.`,
);
}
if (!ignoreSetState) {
// We always assign it as we mutate rows for perf reason.
apiRef.current.state = newState;
if (apiRef.current.publishEvent) {
apiRef.current.publishEvent('stateChange', newState);
}
}
if (updatedControlStateIds.length === 1) {
const { stateId, hasPropChanged } = updatedControlStateIds[0];
const controlState = controlStateMapRef.current[stateId];
const model = controlState.stateSelector(newState, apiRef.current.instanceId);
if (controlState.propOnChange && hasPropChanged) {
const details =
props.signature === GridSignature.DataGridPro
? { api: apiRef.current, reason }
: { reason };
controlState.propOnChange(model, details);
}
if (!ignoreSetState) {
apiRef.current.publishEvent(controlState.changeEvent, model, { reason });
}
}
return !ignoreSetState;
},
[apiRef, props.signature],
);
const updateControlState = React.useCallback<
GridStatePrivateApi<PrivateApi['state']>['updateControlState']
>(
(key, state, reason) => {
return apiRef.current.setState((previousState: PrivateApi['state']) => {
return { ...previousState, [key]: state(previousState[key]) };
}, reason);
},
[apiRef],
);
const forceUpdate = React.useCallback(() => rawForceUpdate(() => apiRef.current.state), [apiRef]);
const publicStateApi: Omit<GridStateApi<PrivateApi['state']>, 'state'> = {
setState,
forceUpdate,
};
const privateStateApi: GridStatePrivateApi<PrivateApi['state']> = {
updateControlState,
registerControlState,
};
useGridApiMethod(apiRef, publicStateApi as any, 'public');
useGridApiMethod(apiRef, privateStateApi as any, 'private');
};