[sqllab] optimizing React (#1438)

* [sqllab] optimizing React

* Addressing comments and making npm run dev faster
This commit is contained in:
Maxime Beauchemin
2016-10-26 17:41:46 -07:00
committed by GitHub
parent 64d196442f
commit b24206387b
20 changed files with 133 additions and 75 deletions

View File

@@ -0,0 +1,51 @@
import React from 'react';
import AceEditor from 'react-ace';
import 'brace/mode/sql';
import 'brace/theme/github';
import 'brace/ext/language_tools';
const propTypes = {
sql: React.PropTypes.string.isRequired,
onBlur: React.PropTypes.func,
};
const defaultProps = {
onBlur: () => {},
};
class AceEditorWrapper extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
sql: props.sql,
};
}
textChange(text) {
this.setState({ sql: text });
}
onBlur() {
this.props.onBlur(this.state.sql);
}
render() {
return (
<AceEditor
mode="sql"
theme="github"
onBlur={this.onBlur.bind(this)}
minLines={8}
maxLines={30}
onChange={this.textChange.bind(this)}
height="200px"
width="100%"
editorProps={{ $blockScrolling: true }}
enableBasicAutocompletion
value={this.state.sql}
/>
);
}
}
AceEditorWrapper.defaultProps = defaultProps;
AceEditorWrapper.propTypes = propTypes;
export default AceEditorWrapper;

View File

@@ -1,7 +1,7 @@
import React from 'react';
import { Alert } from 'react-bootstrap';
class Alerts extends React.Component {
class Alerts extends React.PureComponent {
removeAlert(alert) {
this.props.actions.removeAlert(alert);
}

View File

@@ -10,7 +10,7 @@ import DataPreviewModal from './DataPreviewModal';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
class App extends React.Component {
class App extends React.PureComponent {
constructor(props) {
super(props);
this.state = {

View File

@@ -10,7 +10,7 @@ const defaultProps = {
queryEditor: null,
};
export default class CopyQueryTabUrl extends React.Component {
export default class CopyQueryTabUrl extends React.PureComponent {
constructor(props) {
super(props);
this.state = {

View File

@@ -13,7 +13,7 @@ const propTypes = {
dataPreviewQueryId: React.PropTypes.string,
};
class DataPreviewModal extends React.Component {
class DataPreviewModal extends React.PureComponent {
hide() {
this.props.actions.hideDataPreview();
}

View File

@@ -2,7 +2,7 @@ const $ = window.$ = require('jquery');
import React from 'react';
import Select from 'react-select';
class DatabaseSelect extends React.Component {
class DatabaseSelect extends React.PureComponent {
constructor(props) {
super(props);
this.state = {

View File

@@ -20,7 +20,7 @@ const defaultProps = {
};
class Link extends React.Component {
class Link extends React.PureComponent {
render() {
let tooltip = (
<Tooltip id="tooltip">

View File

@@ -7,7 +7,7 @@ const $ = require('jquery');
const QUERY_UPDATE_FREQ = 1000;
const QUERY_UPDATE_BUFFER_MS = 5000;
class QueryAutoRefresh extends React.Component {
class QueryAutoRefresh extends React.PureComponent {
componentWillMount() {
this.startTimer();
}

View File

@@ -11,7 +11,7 @@ const propTypes = {
actions: React.PropTypes.object.isRequired,
};
class QuerySearch extends React.Component {
class QuerySearch extends React.PureComponent {
constructor(props) {
super(props);
this.state = {

View File

@@ -27,7 +27,7 @@ const defaultProps = {
};
class QueryTable extends React.Component {
class QueryTable extends React.PureComponent {
constructor(props) {
super(props);
const uri = window.location.toString();

View File

@@ -25,7 +25,7 @@ const defaultProps = {
};
class ResultSet extends React.Component {
class ResultSet extends React.PureComponent {
constructor(props) {
super(props);
this.state = {

View File

@@ -1,6 +1,7 @@
import { Alert, Tab, Tabs } from 'react-bootstrap';
import QueryHistory from './QueryHistory';
import ResultSet from './ResultSet';
import { areArraysShallowEqual } from '../../reduxUtils';
import React from 'react';
import shortid from 'shortid';
@@ -10,32 +11,40 @@ const propTypes = {
actions: React.PropTypes.object.isRequired,
};
const SouthPane = function (props) {
let latestQuery;
if (props.queries.length > 0) {
latestQuery = props.queries[props.queries.length - 1];
class SouthPane extends React.PureComponent {
shouldComponentUpdate(nextProps) {
return !areArraysShallowEqual(this.props.queries, nextProps.queries);
}
let results;
if (latestQuery) {
results = <ResultSet showControls search query={latestQuery} actions={props.actions} />;
} else {
results = <Alert bsStyle="info">Run a query to display results here</Alert>;
render() {
let latestQuery;
const props = this.props;
if (props.queries.length > 0) {
latestQuery = props.queries[props.queries.length - 1];
}
let results;
if (latestQuery) {
results = (
<ResultSet showControls search query={latestQuery} actions={props.actions} />
);
} else {
results = <Alert bsStyle="info">Run a query to display results here</Alert>;
}
return (
<div className="SouthPane">
<Tabs bsStyle="tabs" id={shortid.generate()}>
<Tab title="Results" eventKey={1}>
<div style={{ overflow: 'auto' }}>
{results}
</div>
</Tab>
<Tab title="Query History" eventKey={2}>
<QueryHistory queries={props.queries} actions={props.actions} />
</Tab>
</Tabs>
</div>
);
}
return (
<div className="SouthPane">
<Tabs bsStyle="tabs" id={shortid.generate()}>
<Tab title="Results" eventKey={1}>
<div style={{ overflow: 'auto' }}>
{results}
</div>
</Tab>
<Tab title="Query History" eventKey={2}>
<QueryHistory queries={props.queries} actions={props.actions} />
</Tab>
</Tabs>
</div>
);
};
}
SouthPane.propTypes = propTypes;
export default SouthPane;

View File

@@ -13,16 +13,11 @@ import {
Tooltip,
} from 'react-bootstrap';
import AceEditor from 'react-ace';
import 'brace/mode/sql';
import 'brace/theme/github';
import 'brace/ext/language_tools';
import shortid from 'shortid';
import SouthPane from './SouthPane';
import Timer from './Timer';
import SqlEditorLeftBar from './SqlEditorLeftBar';
import AceEditorWrapper from './AceEditorWrapper';
const propTypes = {
actions: React.PropTypes.object.isRequired,
@@ -41,12 +36,11 @@ const defaultProps = {
};
class SqlEditor extends React.Component {
class SqlEditor extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
autorun: props.queryEditor.autorun,
sql: props.queryEditor.sql,
ctas: '',
};
}
@@ -82,16 +76,12 @@ class SqlEditor extends React.Component {
createTableAs() {
this.startQuery(true, true);
}
textChange(text) {
this.setState({ sql: text });
this.props.actions.queryEditorSetSql(this.props.queryEditor, text);
setQueryEditorSql(sql) {
this.props.actions.queryEditorSetSql(this.props.queryEditor, sql);
}
ctasChange() {}
visualize() {}
ctasChanged(event) {
this.setState({ ctas: event.target.value });
}
sqlEditorHeight() {
// quick hack to make the white bg of the tab stretch full height.
const tabNavHeight = 40;
@@ -110,7 +100,7 @@ class SqlEditor extends React.Component {
style={{ width: '100px' }}
onClick={this.runQuery.bind(this, false)}
disabled={!(this.props.queryEditor.dbId)}
key={shortid.generate()}
key="run-btn"
>
<i className="fa fa-table" /> Run Query
</Button>
@@ -124,7 +114,7 @@ class SqlEditor extends React.Component {
style={{ width: '100px' }}
onClick={this.runQuery.bind(this, true)}
disabled={!(this.props.queryEditor.dbId)}
key={shortid.generate()}
key="run-async-btn"
>
<i className="fa fa-table" /> Run Async
</Button>
@@ -217,18 +207,9 @@ class SqlEditor extends React.Component {
/>
</Col>
<Col md={9}>
<AceEditor
mode="sql"
name={this.props.queryEditor.id}
theme="github"
minLines={7}
maxLines={30}
onChange={this.textChange.bind(this)}
height="200px"
width="100%"
editorProps={{ $blockScrolling: true }}
enableBasicAutocompletion
value={this.props.queryEditor.sql}
<AceEditorWrapper
sql={this.props.queryEditor.sql}
onBlur={this.setQueryEditorSql.bind(this)}
/>
{editorBottomBar}
<br />

View File

@@ -1,6 +1,5 @@
const $ = window.$ = require('jquery');
import React from 'react';
import Select from 'react-select';
import { Label, Button } from 'react-bootstrap';
import TableElement from './TableElement';
@@ -19,7 +18,7 @@ const defaultProps = {
actions: {},
};
class SqlEditorLeftBar extends React.Component {
class SqlEditorLeftBar extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
@@ -27,6 +26,7 @@ class SqlEditorLeftBar extends React.Component {
schemaOptions: [],
tableLoading: false,
tableOptions: [],
networkOn: true,
};
}
componentWillMount() {
@@ -92,8 +92,8 @@ class SqlEditorLeftBar extends React.Component {
this.setState({ tableLoading: true });
$.get(url, (data) => {
this.props.actions.mergeTable(Object.assign(data, {
dbId: this.props.queryEditor.dbId,
queryEditorId: this.props.queryEditor.id,
dbId: qe.dbId,
queryEditorId: qe.id,
schema: qe.schema,
expanded: true,
}));
@@ -163,7 +163,6 @@ class SqlEditorLeftBar extends React.Component {
isLoading={this.state.tableLoading}
placeholder={`Add a table (${this.state.tableOptions.length})`}
autosize={false}
value={this.state.tableName}
onChange={this.changeTable.bind(this)}
options={this.state.tableOptions}
/>
@@ -173,7 +172,6 @@ class SqlEditorLeftBar extends React.Component {
{this.props.tables.map((table) => (
<TableElement
table={table}
queryEditor={this.props.queryEditor}
key={table.id}
actions={this.props.actions}
/>

View File

@@ -23,7 +23,7 @@ const defaultProps = {
let queryCount = 1;
class TabbedSqlEditors extends React.Component {
class TabbedSqlEditors extends React.PureComponent {
constructor(props) {
super(props);
const uri = window.location.toString();

View File

@@ -9,7 +9,6 @@ import ModalTrigger from '../../components/ModalTrigger';
const propTypes = {
table: React.PropTypes.object,
queryEditor: React.PropTypes.object,
actions: React.PropTypes.object,
};
@@ -18,7 +17,7 @@ const defaultProps = {
actions: {},
};
class TableElement extends React.Component {
class TableElement extends React.PureComponent {
popSelectStar() {
const qe = {
@@ -46,7 +45,7 @@ class TableElement extends React.Component {
}
dataPreviewModal() {
const query = {
dbId: this.props.queryEditor.dbId,
dbId: this.props.table.dbId,
sql: this.props.table.selectStar,
tableName: this.props.table.name,
sqlEditorId: null,

View File

@@ -3,7 +3,7 @@ import { now, fDuration } from '../../modules/dates';
import { STATE_BSSTYLE_MAP } from '../common.js';
class Timer extends React.Component {
class Timer extends React.PureComponent {
constructor(props) {
super(props);
this.state = {

View File

@@ -23,7 +23,7 @@ const defaultProps = {
onHide: () => {},
};
class VisualizeModal extends React.Component {
class VisualizeModal extends React.PureComponent {
constructor(props) {
super(props);
const uniqueId = shortid.generate();