store 回收问题修复

This commit is contained in:
liaoxuezhi 2019-12-15 17:38:04 +08:00
parent 420aef95ce
commit 8ec9ad0cb3
7 changed files with 144 additions and 115 deletions

View File

@ -56,7 +56,6 @@
"react-addons-update": "15.6.2",
"react-color": "2.13.8",
"react-cropper": "1.0.0",
"react-date-range": "0.9.4",
"react-datetime": "2.16.0",
"react-dom": "^16.8.6",
"react-dropzone": "10.1.10",

View File

@ -734,7 +734,7 @@ export default class ComboControl extends React.Component<ComboProps> {
wrapWithPanel: false,
mode: subFormMode,
className: cx(`Combo-form`, formClassName),
lazyOnChange: false
lazyChange: false
},
{
index,
@ -907,7 +907,7 @@ export default class ComboControl extends React.Component<ComboProps> {
wrapWithPanel: false,
mode: multiLine ? subFormMode : 'row',
className: cx(`Combo-form`, formClassName),
lazyOnChange: false
lazyChange: false
},
{
index,
@ -1043,7 +1043,7 @@ export default class ComboControl extends React.Component<ComboProps> {
wrapWithPanel: false,
mode: multiLine ? 'normal' : 'row',
className: cx(`Combo-form`, formClassName),
lazyOnChange: false
lazyChange: false
},
{
disabled: disabled,

View File

@ -52,8 +52,14 @@ export default class FormControl extends React.PureComponent<
static defaultProps = {};
lazyValidate: Function;
lazyEmitChange: (submitOnChange: boolean) => void;
lazyValidate = debouce(this.validate.bind(this), 250, {
trailing: true,
leading: false
});
lazyEmitChange = debouce(this.emitChange.bind(this), 250, {
trailing: true,
leading: false
});
state = {value: this.props.control.value};
componentWillMount() {
const {
@ -83,14 +89,6 @@ export default class FormControl extends React.PureComponent<
this.setPrinstineValue = this.setPrinstineValue.bind(this);
this.controlRef = this.controlRef.bind(this);
this.handleBlur = this.handleBlur.bind(this);
this.lazyValidate = debouce(this.validate.bind(this), 250, {
trailing: true,
leading: false
});
this.lazyEmitChange = debouce(this.emitChange.bind(this), 250, {
trailing: true,
leading: false
});
if (!name) {
return;
@ -165,43 +163,43 @@ export default class FormControl extends React.PureComponent<
const props = this.props;
const form = nextProps.formStore;
if (!nextProps.control.name) {
// 把 name 删了, 对 model 做清理
this.model && this.disposeModel();
this.reaction && this.reaction();
this.model = undefined;
return;
} else if (nextProps.control.name !== props.control.name || !this.model) {
// 对 model 做清理
this.model && this.disposeModel();
this.reaction && this.reaction();
// if (!nextProps.control.name) {
// // 把 name 删了, 对 model 做清理
// this.model && this.disposeModel();
// this.reaction && this.reaction();
// this.model = undefined;
// return;
// } else if (nextProps.control.name !== props.control.name || !this.model) {
// // 对 model 做清理
// this.model && this.disposeModel();
// this.reaction && this.reaction();
// name 是后面才有的,比如编辑模式下就会出现。
const model = (this.model = form.registryItem(nextProps.control.name, {
id: nextProps.control.id,
type: nextProps.control.type,
required: nextProps.control.required,
unique: nextProps.control.unique,
value: nextProps.control.value,
rules: nextProps.control.validations,
multiple: nextProps.control.multiple,
delimiter: nextProps.control.delimiter,
valueField: nextProps.control.valueField,
labelField: nextProps.control.labelField,
joinValues: nextProps.control.joinValues,
extractValue: nextProps.control.extractValue,
messages: nextProps.control.validationErrors
}));
// this.forceUpdate();
this.setState({
value: model.value
});
// // name 是后面才有的,比如编辑模式下就会出现。
// const model = (this.model = form.registryItem(nextProps.control.name, {
// id: nextProps.control.id,
// type: nextProps.control.type,
// required: nextProps.control.required,
// unique: nextProps.control.unique,
// value: nextProps.control.value,
// rules: nextProps.control.validations,
// multiple: nextProps.control.multiple,
// delimiter: nextProps.control.delimiter,
// valueField: nextProps.control.valueField,
// labelField: nextProps.control.labelField,
// joinValues: nextProps.control.joinValues,
// extractValue: nextProps.control.extractValue,
// messages: nextProps.control.validationErrors
// }));
// // this.forceUpdate();
// this.setState({
// value: model.value
// });
this.reaction = reaction(
() => model.value,
value => this.setState({value})
);
}
// this.reaction = reaction(
// () => model.value,
// value => this.setState({value})
// );
// }
if (
this.model &&
@ -268,10 +266,11 @@ export default class FormControl extends React.PureComponent<
componentWillUnmount() {
this.hook && this.props.removeHook(this.hook);
this.hook2 && this.props.removeHook(this.hook2);
this.disposeModel();
this.lazyValidate.cancel();
// this.lazyEmitChange.flush();
this.lazyEmitChange.cancel();
this.reaction && this.reaction();
(this.lazyValidate as any).cancel();
(this.lazyEmitChange as any).cancel();
this.disposeModel();
}
disposeModel() {
@ -348,7 +347,7 @@ export default class FormControl extends React.PureComponent<
const {
formStore: form,
onChange,
control: {type, pipeOut},
control: {type, pipeOut, changeImmediately: conrolChangeImmediately},
formInited
} = this.props;
@ -368,7 +367,7 @@ export default class FormControl extends React.PureComponent<
value
},
() =>
changeImmediately || !formInited
changeImmediately || conrolChangeImmediately || !formInited
? this.emitChange(submitOnChange)
: this.lazyEmitChange(submitOnChange)
);
@ -521,7 +520,6 @@ export default class FormControl extends React.PureComponent<
return render('', control, {
...rest,
key: `${control.name || ''}-${control.type}`, // 很重要:如果不写实际的 control 组件变了,但是 this.control 还是引用的原来那个。
defaultSize: controlWidth,
disabled: disabled || control.disabled,
formItem: model,

View File

@ -152,7 +152,7 @@ export default class Form extends React.Component<FormProps, object> {
'onFailed',
'onFinished',
'canAccessSuperData',
'lazyOnChange'
'lazyChange'
];
hooks: {
@ -163,7 +163,10 @@ export default class Form extends React.Component<FormProps, object> {
shouldLoadInitApi: boolean = false;
timer: NodeJS.Timeout;
mounted: boolean;
lazyHandleChange: (value: any, name: string, submit: boolean) => void;
lazyHandleChange = debouce(this.handleChange.bind(this), 250, {
trailing: true,
leading: false
});
constructor(props: FormProps) {
super(props);
@ -179,10 +182,6 @@ export default class Form extends React.Component<FormProps, object> {
this.addHook = this.addHook.bind(this);
this.removeHook = this.removeHook.bind(this);
this.handleChange = this.handleChange.bind(this);
this.lazyHandleChange = debouce(this.handleChange, 250, {
trailing: true,
leading: false
});
this.renderFormItems = this.renderFormItems.bind(this);
this.reload = this.reload.bind(this);
this.silentReload = this.silentReload.bind(this);
@ -303,7 +302,8 @@ export default class Form extends React.Component<FormProps, object> {
componentWillUnmount() {
this.mounted = false;
clearTimeout(this.timer);
(this.lazyHandleChange as any).cancel();
// this.lazyHandleChange.flush();
this.lazyHandleChange.cancel();
this.asyncCancel && this.asyncCancel();
this.disposeOnValidate && this.disposeOnValidate();
const store = this.props.store;
@ -896,13 +896,15 @@ export default class Form extends React.Component<FormProps, object> {
disabled,
controlWidth,
resolveDefinitions,
lazyOnChange
lazyChange
} = props;
const subProps = {
formStore: form,
data: store.data,
key,
key: `${(control as Schema).name || ''}-${
(control as Schema).type
}-${key}`,
formInited: form.inited,
formMode: mode,
formHorizontal: horizontal,
@ -910,8 +912,7 @@ export default class Form extends React.Component<FormProps, object> {
disabled: disabled || (control as Schema).disabled || form.loading,
btnDisabled: form.loading || form.validating,
onAction: this.handleAction,
onChange:
lazyOnChange !== false ? this.lazyHandleChange : this.handleChange,
onChange: this.lazyHandleChange,
addHook: this.addHook,
removeHook: this.removeHook,
renderFormItems: this.renderFormItems,
@ -919,7 +920,7 @@ export default class Form extends React.Component<FormProps, object> {
};
const subSchema: any =
control && (control as Schema).type === 'control'
(control as Schema).type === 'control'
? control
: {
type: 'control',
@ -944,6 +945,7 @@ export default class Form extends React.Component<FormProps, object> {
control.hiddenOn && (subSchema.hiddenOn = control.hiddenOn);
control.visibleOn && (subSchema.visibleOn = control.visibleOn);
lazyChange === false && (control.changeImmediately = true);
}
return render(`${region ? `${region}/` : ''}${key}`, subSchema, subProps);
@ -956,46 +958,23 @@ export default class Form extends React.Component<FormProps, object> {
controls,
mode,
className,
classnames: cx
} = this.props;
return (
<div className={cx(`Form`, `Form--${mode || 'normal'}`, className)}>
{this.renderFormItems({
tabs,
fieldSet,
controls
})}
</div>
);
}
render() {
const {
className,
wrapWithPanel,
render,
title,
store,
panelClassName,
debug,
headerClassName,
footerClassName,
actionsClassName,
bodyClassName,
classPrefix: ns,
classnames: cx,
debug,
$path,
affixFooter,
mode
store,
render
} = this.props;
const WrapperComponent =
this.props.wrapperComponent ||
(/(?:\/|^)form\//.test($path as string) ? 'div' : 'form');
let body = (
<WrapperComponent onSubmit={this.handleFormSubmit} noValidate>
return (
<WrapperComponent
className={cx(`Form`, `Form--${mode || 'normal'}`, className)}
onSubmit={this.handleFormSubmit}
noValidate
>
{debug ? (
<pre>
<code>{JSON.stringify(store.data, null, 2)}</code>
@ -1004,7 +983,11 @@ export default class Form extends React.Component<FormProps, object> {
<Spinner show={store.loading} overlay />
{this.renderBody()}
{this.renderFormItems({
tabs,
fieldSet,
controls
})}
{render(
'modal',
@ -1039,6 +1022,24 @@ export default class Form extends React.Component<FormProps, object> {
)}
</WrapperComponent>
);
}
render() {
const {
wrapWithPanel,
render,
title,
store,
panelClassName,
headerClassName,
footerClassName,
actionsClassName,
bodyClassName,
classnames: cx,
affixFooter
} = this.props;
let body: JSX.Element = this.renderBody();
if (wrapWithPanel) {
body = render(
@ -1101,6 +1102,8 @@ export class FormRenderer extends Form {
componentWillUnmount() {
const scoped = this.context as IScopedContext;
scoped.unRegisterComponent(this);
super.componentWillUnmount();
}
doAction(action: Action, data: object, throwErrors: boolean = false) {

View File

@ -42,7 +42,7 @@ export interface FlvSourceProps {
order?: number;
}
let currentPlaying: any = null;
// let currentPlaying: any = null;
export class FlvSource extends React.Component<FlvSourceProps, any> {
flvPlayer: any;
@ -262,17 +262,17 @@ export default class Video extends React.Component<VideoProps, VideoState> {
videoState: state
});
if (!state.paused) {
if (
currentPlaying &&
currentPlaying.video &&
currentPlaying !== player
) {
currentPlaying.pause();
}
// if (!state.paused) {
// if (
// currentPlaying &&
// currentPlaying.video &&
// currentPlaying !== player
// ) {
// currentPlaying.pause();
// }
currentPlaying = player;
}
// currentPlaying = player;
// }
if (!this.frameDom || !this.times) {
return;

View File

@ -1,4 +1,4 @@
import {types, getRoot, Instance} from 'mobx-state-tree';
import {types, getRoot, Instance, destroy} from 'mobx-state-tree';
import {extendObject, createObject} from '../utils/helper';
import {IRendererStore} from './index';
import {dataMapping} from '../utils/tpl-builtin';
@ -13,7 +13,9 @@ export const iRendererStore = types
data: types.optional(types.frozen(), {}),
updatedAt: 0, // 从服务端更新时刻
pristine: types.optional(types.frozen(), {}),
parentId: types.optional(types.string, ''),
disposed: false,
parentId: '',
childrenIds: types.optional(types.array(types.string), []),
action: types.optional(types.frozen(), undefined),
dialogOpen: false,
dialogData: types.optional(types.frozen(), undefined),
@ -35,6 +37,18 @@ export const iRendererStore = types
.actions(self => {
const dialogCallbacks = new SimpleMap<(result?: any) => void>();
function dispose() {
// 先标记自己是要销毁的。
self.disposed = true;
const parent = self.parentStore;
if (!self.childrenIds.length) {
const id = self.id;
destroy(self);
parent && parent.onChildDispose(id);
}
}
return {
initData(data: object = {}) {
self.pristine = data;
@ -152,7 +166,16 @@ export const iRendererStore = types
dialogCallbacks.delete(self.drawerData);
setTimeout(() => callback(result), 200);
}
}
},
onChildDispose(childId: string) {
const childrenIds = self.childrenIds.filter(item => item !== childId);
self.childrenIds.replace(childrenIds);
self.disposed && dispose();
},
dispose
};
});

View File

@ -68,12 +68,18 @@ export const RendererStore = types
if (self.stores.has(store.id as string)) {
return self.stores.get(store.id) as IIRendererStore;
}
if (store.parentId) {
const parent = self.stores.get(store.parentId) as IIRendererStore;
parent.childrenIds.push(store.id);
}
self.stores.put(store);
return self.stores.get(store.id) as IIRendererStore;
},
removeStore(store: IIRendererStore) {
detach(store);
store.dispose();
}
}));