Improve GenericExpressionField performance

This commit is contained in:
Florian Rival
2018-03-10 22:10:39 +01:00
parent da9eb3cea7
commit 01e2b53a3f
2 changed files with 49 additions and 27 deletions

View File

@@ -1,12 +1,14 @@
// @flow weak
// @flow
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import TextField from 'material-ui/TextField';
import Popover, { PopoverAnimationVertical } from 'material-ui/Popover';
import Functions from 'material-ui/svg-icons/editor/functions';
import RaisedButton from 'material-ui/RaisedButton';
import SemiControlledTextField from '../../../../UI/SemiControlledTextField';
import ExpressionSelector from '../../InstructionOrExpressionSelector/ExpressionSelector';
import ExpressionParametersEditorDialog from './ExpressionParametersEditorDialog';
import ExpressionParametersEditorDialog, {
type ParameterValues,
} from './ExpressionParametersEditorDialog';
import { formatExpressionCall } from './FormatExpressionCall';
import { type InstructionOrExpressionInformation } from '../../InstructionOrExpressionSelector/InstructionOrExpressionInformation.flow.js';
const gd = global.gd;
@@ -44,8 +46,8 @@ type State = {|
|};
export default class ExpressionField extends Component<*, State> {
_field = null;
_fieldElement = null;
_field: ?any = null;
_fieldElement: ?any = null;
_inputElement = null;
state = {
@@ -58,7 +60,7 @@ export default class ExpressionField extends Component<*, State> {
componentDidMount() {
if (this._field) {
this._fieldElement = ReactDOM.findDOMNode(this._field);
this._inputElement = this._field.getInputNode();
this._inputElement = this._field ? this._field.getInputNode() : null;
}
}
@@ -72,34 +74,32 @@ export default class ExpressionField extends Component<*, State> {
});
};
_handleFocus = event => {
_handleFocus = (event: any) => {
// This prevents ghost click.
event.preventDefault();
};
_handleBlur = () => {
this._doValidation();
this.setState({
popoverOpen: false,
});
};
_handleRequestClose = () => {
this.setState({
popoverOpen: false,
});
};
_handleChange = (e, text) => {
if (this.props.onChange) this.props.onChange(text);
_handleChange = (value: string) => {
if (this.props.onChange) this.props.onChange(value);
this._doValidation(value);
this.setState({
popoverOpen: false,
});
};
_handleMenuMouseDown = event => {
_handleMenuMouseDown = (event: any) => {
// Keep the TextField focused
event.preventDefault();
};
_handleExpressionChosen = expressionInfo => {
_handleExpressionChosen = (expressionInfo: InstructionOrExpressionInformation) => {
this.setState({
popoverOpen: false,
parametersDialogOpen: true,
@@ -107,7 +107,10 @@ export default class ExpressionField extends Component<*, State> {
});
};
insertExpression = (expressionInfo, parameterValues) => {
insertExpression = (
expressionInfo: InstructionOrExpressionInformation,
parameterValues: ParameterValues
) => {
if (!this._inputElement) return;
const cursorPosition = this._inputElement.selectionStart;
@@ -133,14 +136,16 @@ export default class ExpressionField extends Component<*, State> {
}, 5);
};
_getError = () => {
_getError = (value?: string) => {
const { project, layout, expressionType } = this.props;
const callbacks = new gd.CallbacksForExpressionCorrectnessTesting(
project,
layout
);
const parser = new gd.ExpressionParser(this.props.value);
const parser = new gd.ExpressionParser(
value === undefined ? this.props.value : value
);
const parseFunction =
expressionType === 'string'
@@ -161,8 +166,8 @@ export default class ExpressionField extends Component<*, State> {
return isValid ? null : error;
};
_doValidation = () => {
this.setState({ errorText: this._getError() });
_doValidation = (value?: string) => {
this.setState({ errorText: this._getError(value) });
};
render() {
@@ -185,14 +190,14 @@ export default class ExpressionField extends Component<*, State> {
return (
<div style={styles.container}>
<div style={styles.textFieldContainer}>
<TextField
<SemiControlledTextField
commitOnBlur
value={value}
floatingLabelText={description}
inputStyle={styles.input}
onChange={this._handleChange}
ref={field => (this._field = field)}
onFocus={this._handleFocus}
onBlur={this._handleBlur}
errorText={this.state.errorText}
fullWidth
/>

View File

@@ -6,6 +6,8 @@ type State = {
focused: boolean,
text: ?string,
commitOnBlur?: boolean,
onFocus?: Function,
onBlur?: Function,
};
/**
@@ -20,18 +22,31 @@ export default class SemiControlledTextField extends React.Component<*, State> {
text: null,
};
_field: ?any = null;
focus() {
if (this._field) this._field.focus();
}
getInputNode() {
if (this._field) return this._field.getInputNode();
}
render() {
const { value, onChange, commitOnBlur, ...otherProps } = this.props;
const { value, onChange, commitOnBlur, onFocus, onBlur, ...otherProps } = this.props;
return (
<TextField
{...otherProps}
ref={field => this._field = field}
value={this.state.focused ? this.state.text : value}
onFocus={() => {
onFocus={(event) => {
this.setState({
focused: true,
text: this.props.value,
});
if (onFocus) onFocus(event);
}}
onChange={(event, newValue) => {
this.setState({
@@ -46,6 +61,8 @@ export default class SemiControlledTextField extends React.Component<*, State> {
focused: false,
text: null,
});
if (onBlur) onBlur(event);
}}
/>
);