Upgrade React to v16

* Introduce 2 base components: Component and PureComponent. Before, we have only PureComponent but it was impossible to add a shoulComponentUpdate method (used for Terms).
This commit is contained in:
CHaBou 2017-09-16 21:17:22 +02:00
parent 507fc28200
commit f8366d010d
No known key found for this signature in database
GPG key ID: EF8D073B729A0B33
15 changed files with 103 additions and 107 deletions

69
lib/base-components.js Normal file
View file

@ -0,0 +1,69 @@
import React from 'react';
import {StyleSheet, css} from 'aphrodite-simple';
const decorateBaseComponent = Component => {
return class BaseComponent extends Component {
constructor() {
super();
this.styles_ = this.createStyleSheet();
this.cssHelper = this.cssHelper.bind(this);
}
createStyleSheet() {
if (!this.styles) {
return {};
}
const styles = this.styles();
if (typeof styles !== 'object') {
throw new TypeError('Component `styles` returns a non-object');
}
return StyleSheet.create(this.styles());
}
// wrap aphrodite's css helper for two reasons:
// - we can give the element an unaltered global classname
// that can be used to introduce global css side effects
// for example, through the configuration, web inspector
// or user agent extensions
// - the user doesn't need to keep track of both `css`
// and `style`, and we make that whole ordeal easier
cssHelper(...args) {
const classes = args
.map(c => {
if (c) {
// we compute the global name from the given
// css class and we prepend the component name
//
// it's important classes never get mangled by
// uglifiers so that we can avoid collisions
const component = this.constructor.name.toString().toLowerCase();
const globalName = `${component}_${c}`;
return [globalName, css(this.styles_[c])];
}
return null;
})
// skip nulls
.filter(v => Boolean(v))
// flatten
.reduce((a, b) => a.concat(b));
return classes.length ? classes.join(' ') : null;
}
render() {
// convert static objects from `babel-plugin-transform-jsx`
// to `React.Element`.
if (!this.template) {
throw new TypeError("Component doesn't define `template`");
}
// invoke the template creator passing our css helper
return this.template(this.cssHelper);
}
};
};
export const PureComponent = decorateBaseComponent(React.PureComponent);
export const Component = decorateBaseComponent(React.Component);

View file

@ -1,64 +0,0 @@
import React from 'react';
import {StyleSheet, css} from 'aphrodite-simple';
export default class Component extends React.PureComponent {
constructor() {
super();
this.styles_ = this.createStyleSheet();
this.cssHelper = this.cssHelper.bind(this);
}
createStyleSheet() {
if (!this.styles) {
return {};
}
const styles = this.styles();
if (typeof styles !== 'object') {
throw new TypeError('Component `styles` returns a non-object');
}
return StyleSheet.create(this.styles());
}
// wrap aphrodite's css helper for two reasons:
// - we can give the element an unaltered global classname
// that can be used to introduce global css side effects
// for example, through the configuration, web inspector
// or user agent extensions
// - the user doesn't need to keep track of both `css`
// and `style`, and we make that whole ordeal easier
cssHelper(...args) {
const classes = args
.map(c => {
if (c) {
// we compute the global name from the given
// css class and we prepend the component name
//
// it's important classes never get mangled by
// uglifiers so that we can avoid collisions
const component = this.constructor.name.toString().toLowerCase();
const globalName = `${component}_${c}`;
return [globalName, css(this.styles_[c])];
}
return null;
})
// skip nulls
.filter(v => Boolean(v))
// flatten
.reduce((a, b) => a.concat(b));
return classes.length ? classes.join(' ') : null;
}
render() {
// convert static objects from `babel-plugin-transform-jsx`
// to `React.Element`.
if (!this.template) {
throw new TypeError("Component doesn't define `template`");
}
// invoke the template creator passing our css helper
return this.template(this.cssHelper);
}
}

View file

@ -1,13 +1,13 @@
import React from 'react';
import Component from '../component';
import {PureComponent} from '../base-components';
import {decorate, getTabsProps} from '../utils/plugins';
import Tabs_ from './tabs';
const Tabs = decorate(Tabs_, 'Tabs');
export default class Header extends Component {
export default class Header extends PureComponent {
constructor() {
super();
this.onChangeIntent = this.onChangeIntent.bind(this);

View file

@ -1,7 +1,7 @@
import React from 'react';
import Component from '../component';
import {PureComponent} from '../base-components';
export default class Notification extends Component {
export default class Notification extends PureComponent {
constructor() {
super();
this.state = {

View file

@ -1,13 +1,13 @@
import React from 'react';
import Component from '../component';
import {PureComponent} from '../base-components';
import {decorate} from '../utils/plugins';
import Notification_ from './notification';
const Notification = decorate(Notification_);
export default class Notifications extends Component {
export default class Notifications extends PureComponent {
template(css) {
return (
<div className={css('view')}>

View file

@ -1,8 +1,8 @@
/* eslint-disable quote-props */
import React from 'react';
import Component from '../component';
import {PureComponent} from '../base-components';
export default class SplitPane extends Component {
export default class SplitPane extends PureComponent {
constructor(props) {
super(props);
this.handleDragStart = this.handleDragStart.bind(this);

View file

@ -1,7 +1,7 @@
import React from 'react';
import Component from '../component';
import {PureComponent} from '../base-components';
export default class Tab extends Component {
export default class Tab extends PureComponent {
constructor() {
super();

View file

@ -1,6 +1,6 @@
import React from 'react';
import Component from '../component';
import {PureComponent} from '../base-components';
import {decorate, getTabProps} from '../utils/plugins';
import Tab_ from './tab';
@ -8,7 +8,7 @@ import Tab_ from './tab';
const Tab = decorate(Tab_, 'Tab');
const isMac = /Mac/.test(navigator.userAgent);
export default class Tabs extends Component {
export default class Tabs extends PureComponent {
template(css) {
const {tabs = [], borderColor, onChange, onClose} = this.props;

View file

@ -1,6 +1,6 @@
import React from 'react';
import {connect} from 'react-redux';
import Component from '../component';
import {PureComponent} from '../base-components';
import {decorate, getTermProps, getTermGroupProps} from '../utils/plugins';
import {resizeTermGroup} from '../actions/term-groups';
import Term_ from './term';
@ -9,7 +9,7 @@ import SplitPane_ from './split-pane';
const Term = decorate(Term_, 'Term');
const SplitPane = decorate(SplitPane_, 'SplitPane');
class TermGroup_ extends Component {
class TermGroup_ extends PureComponent {
constructor(props, context) {
super(props, context);
this.bound = new WeakMap();

View file

@ -1,7 +1,7 @@
/* global Blob,URL,requestAnimationFrame */
import React from 'react';
import Terminal from 'xterm';
import Component from '../component';
import {PureComponent} from '../base-components';
import terms from '../terms';
import returnKey from '../utils/keymaps';
import CommandRegistry from '../command-registry';
@ -13,7 +13,7 @@ const CURSOR_STYLES = {
BLOCK: 'block'
};
export default class Term extends Component {
export default class Term extends PureComponent {
constructor(props) {
super(props);
props.ref_(props.uid, this);

View file

@ -1,5 +1,5 @@
import React from 'react';
import Component from '../component';
import {Component} from '../base-components';
import {decorate, getTermGroupProps} from '../utils/plugins';
import CommandRegistry from '../command-registry';
import TermGroup_ from './term-group';

View file

@ -2,7 +2,7 @@
import React from 'react';
import Component from '../component';
import {PureComponent} from '../base-components';
import {connect} from '../utils/plugins';
import * as uiActions from '../actions/ui';
@ -12,7 +12,7 @@ import NotificationsContainer from './notifications';
const isMac = /Mac/.test(navigator.userAgent);
class Hyper extends Component {
class Hyper extends PureComponent {
constructor(props) {
super(props);
this.handleFocusActive = this.handleFocusActive.bind(this);

View file

@ -6,7 +6,7 @@ import {connect as reduxConnect} from 'react-redux';
// https://github.com/zeit/hyper/issues/619
import React from 'react';
import ReactDOM from 'react-dom';
import Component from '../component';
import {PureComponent} from '../base-components';
import Notification from '../components/notification';
import notify from './notify';
@ -20,7 +20,7 @@ Module._load = function _load(path) {
case 'react-dom':
return ReactDOM;
case 'hyper/component':
return Component;
return PureComponent;
case 'hyper/notify':
return notify;
case 'hyper/Notification':
@ -457,7 +457,7 @@ function getDecorated(parent, name) {
let class__;
try {
class__ = fn(class_, {React, Component, Notification, notify});
class__ = fn(class_, {React, PureComponent, Notification, notify});
class__.displayName = `${fn._pluginName}(${name})`;
} catch (err) {
//eslint-disable-next-line no-console

View file

@ -150,9 +150,9 @@
"mousetrap": "1.6.1",
"ms": "2.0.0",
"php-escape-shell": "1.0.0",
"react": "15.6.1",
"react": "16.0.0-rc.3",
"react-deep-force-update": "2.0.1",
"react-dom": "15.6.1",
"react-dom": "16.0.0-rc.3",
"react-redux": "5.0.6",
"redux": "3.7.2",
"redux-thunk": "2.2.0",

View file

@ -1725,14 +1725,6 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
create-react-class@^15.6.0:
version "15.6.0"
resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.6.0.tgz#ab448497c26566e1e29413e883207d57cfe7bed4"
dependencies:
fbjs "^0.8.9"
loose-envify "^1.3.1"
object-assign "^4.1.1"
cross-env@5.0.5:
version "5.0.5"
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.0.5.tgz#4383d364d9660873dd185b398af3bfef5efffef3"
@ -4178,7 +4170,7 @@ oauth-sign@~0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
object-assign@^4.0.1, object-assign@^4.1.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
@ -4814,7 +4806,7 @@ promise@^7.1.1:
dependencies:
asap "~2.0.3"
prop-types@^15.5.10:
prop-types@^15.5.10, prop-types@^15.5.6:
version "15.5.10"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
dependencies:
@ -4896,14 +4888,14 @@ react-deep-force-update@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/react-deep-force-update/-/react-deep-force-update-2.0.1.tgz#4f7f6c12c3e7de42f345992a3c518236fa1ecad3"
react-dom@15.6.1:
version "15.6.1"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.6.1.tgz#2cb0ed4191038e53c209eb3a79a23e2a4cf99470"
react-dom@16.0.0-rc.3:
version "16.0.0-rc.3"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.0.0-rc.3.tgz#bd4e4d2abd464df5149a062b45fe796bbb804c2c"
dependencies:
fbjs "^0.8.9"
loose-envify "^1.1.0"
object-assign "^4.1.0"
prop-types "^15.5.10"
prop-types "^15.5.6"
react-redux@5.0.6:
version "5.0.6"
@ -4916,15 +4908,14 @@ react-redux@5.0.6:
loose-envify "^1.1.0"
prop-types "^15.5.10"
react@15.6.1:
version "15.6.1"
resolved "https://registry.yarnpkg.com/react/-/react-15.6.1.tgz#baa8434ec6780bde997cdc380b79cd33b96393df"
react@16.0.0-rc.3:
version "16.0.0-rc.3"
resolved "https://registry.yarnpkg.com/react/-/react-16.0.0-rc.3.tgz#4a9df996326ba7185903d9fbed3149765e237e26"
dependencies:
create-react-class "^15.6.0"
fbjs "^0.8.9"
loose-envify "^1.1.0"
object-assign "^4.1.0"
prop-types "^15.5.10"
prop-types "^15.5.6"
read-config-file@1.1.0:
version "1.1.0"