Skip to content

Instantly share code, notes, and snippets.

@kentcdodds
Created December 21, 2016 05:54
Show Gist options
  • Save kentcdodds/3a401fad2f8a39f543dbf568378e296e to your computer and use it in GitHub Desktop.
Save kentcdodds/3a401fad2f8a39f543dbf568378e296e to your computer and use it in GitHub Desktop.
esnextbin sketch
<html>
<head>
<link rel="stylesheet" href="https://unpkg.com/milligram@1.2.4" />
</head>
<body>
<div id="root"></div>
</body>
</html>
import React, {Component, PropTypes} from 'react'
import ReactDOM from 'react-dom'
class StateSetter extends Component {
constructor(props, ...rest) {
super(props, ...rest)
this.state = props.initialState || {}
}
render() {
return this.props.children(this.state, (...args) => this.setState(...args))
}
}
function withContext(context) {
class StateSetterWithContext extends StateSetter {
getChildContext() { // eslint-disable-line
return context
}
}
StateSetterWithContext.childContextTypes = Object.keys(context).reduce((types, key) => {
types[key] = PropTypes.any
return types
}, {})
return StateSetterWithContext
}
const context = {
color: 'black',
}
setInterval(() => {
context.color = context.color === 'black' ? 'gray' : 'black'
}, 1000)
const StateSetterWithColorContext = withContext(context)
function getThislessComponent(getModule, staticProperties) {
class Thisless extends React.Component {
constructor(...args) {
super(...args)
const result = getModule(this, ...args)
Object.assign(this, result)
}
}
Object.assign(Thisless, staticProperties)
return Thisless
}
const SmileyFace = getThislessComponent((instance, props) => { // access to props (and context)
let canChangeHappyState = false // legit private property, no extra wacky syntax. Just JavaScript function closures.
// just return React component object
return {
state: {happy: props.initialHappyState}, // basically like public class fields, except no special syntax
onButtonClick() { // no worries about binding this or using public class fields, because you're not using `this`!
if (canChangeHappyState) {
instance.setState({happy: !instance.state.happy})
}
},
componentDidMount() { // Real component lifecycle methods! They all work!
setTimeout(() => {
canChangeHappyState = true
}, 5000)
},
render() {
// access to state, props, and context just like from `this`
// except it's from the `instance`
const {happy} = instance.state
const {clicks} = instance.props
const {color} = instance.context
return (
<div>
<div style={{width: 350}}>
Cannot change happy state for the first 5 seconds due to a genuine
private <code>canChangeHappyState</code> variable, which
is: {JSON.stringify(canChangeHappyState)}
</div>
<button onClick={instance.onButtonClick}>
instance.state.happy: {happy ? ':-)' : ':-('}
</button>
<div>instance.props.clicks: {clicks}</div>
<div style={{color}}>instance.context.color: {color}</div>
</div>
)
},
}
}, { // static properties go here :)
defaultProps: {initialHappyState: true},
propTypes: {initialHappyState: React.PropTypes.bool},
contextTypes: {color: React.PropTypes.string},
})
const root = (
<StateSetterWithColorContext initialState={{clicks: 0}}>
{({clicks}, setState) => (
<div style={{margin: 70}}>
<div style={{marginRight: 20}}>
<button onClick={() => setState({clicks: clicks + 1})}>click me</button>
<SmileyFace clicks={clicks} />
<div style={{width: 400, marginTop: 50}}>
Just experimenting for fun. Please spare me the "what about perf?" and "I don't like this" and
"this isn't really better" or "yeah, duh!" yada yada. I'm just a programmer having some fun... But I
think it's neat! Creating components via the module pattern! Private members are easy and obvious.
State, props, and context all without using `this` or classes. Lifecycle methods work too.
All from 10 lines of code :)
</div>
</div>
</div>
)}
</StateSetterWithColorContext>
)
ReactDOM.render(
root,
document.getElementById('root')
)
{
"name": "esnextbin-sketch",
"version": "0.0.0",
"dependencies": {
"react": "15.4.1",
"react-dom": "15.4.1",
"babel-runtime": "6.20.0"
}
}
'use strict';
var _stringify = require('babel-runtime/core-js/json/stringify');
var _stringify2 = _interopRequireDefault(_stringify);
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);
var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of');
var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _reactDom = require('react-dom');
var _reactDom2 = _interopRequireDefault(_reactDom);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var StateSetter = function (_Component) {
(0, _inherits3.default)(StateSetter, _Component);
function StateSetter(props) {
var _Object$getPrototypeO;
(0, _classCallCheck3.default)(this, StateSetter);
for (var _len = arguments.length, rest = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
rest[_key - 1] = arguments[_key];
}
var _this = (0, _possibleConstructorReturn3.default)(this, (_Object$getPrototypeO = (0, _getPrototypeOf2.default)(StateSetter)).call.apply(_Object$getPrototypeO, [this, props].concat(rest)));
_this.state = props.initialState || {};
return _this;
}
(0, _createClass3.default)(StateSetter, [{
key: 'render',
value: function render() {
var _this2 = this;
return this.props.children(this.state, function () {
return _this2.setState.apply(_this2, arguments);
});
}
}]);
return StateSetter;
}(_react.Component);
function withContext(context) {
var StateSetterWithContext = function (_StateSetter) {
(0, _inherits3.default)(StateSetterWithContext, _StateSetter);
function StateSetterWithContext() {
(0, _classCallCheck3.default)(this, StateSetterWithContext);
return (0, _possibleConstructorReturn3.default)(this, (0, _getPrototypeOf2.default)(StateSetterWithContext).apply(this, arguments));
}
(0, _createClass3.default)(StateSetterWithContext, [{
key: 'getChildContext',
value: function getChildContext() {
// eslint-disable-line
return context;
}
}]);
return StateSetterWithContext;
}(StateSetter);
StateSetterWithContext.childContextTypes = (0, _keys2.default)(context).reduce(function (types, key) {
types[key] = _react.PropTypes.any;
return types;
}, {});
return StateSetterWithContext;
}
var context = {
color: 'black'
};
setInterval(function () {
context.color = context.color === 'black' ? 'gray' : 'black';
}, 1000);
var StateSetterWithColorContext = withContext(context);
function getThislessComponent(getModule, staticProperties) {
var Thisless = function (_React$Component) {
(0, _inherits3.default)(Thisless, _React$Component);
function Thisless() {
var _Object$getPrototypeO2;
(0, _classCallCheck3.default)(this, Thisless);
for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
args[_key2] = arguments[_key2];
}
var _this4 = (0, _possibleConstructorReturn3.default)(this, (_Object$getPrototypeO2 = (0, _getPrototypeOf2.default)(Thisless)).call.apply(_Object$getPrototypeO2, [this].concat(args)));
var result = getModule.apply(undefined, [_this4].concat(args));
(0, _extends3.default)(_this4, result);
return _this4;
}
return Thisless;
}(_react2.default.Component);
(0, _extends3.default)(Thisless, staticProperties);
return Thisless;
}
var SmileyFace = getThislessComponent(function (instance, props) {
// access to props (and context)
var canChangeHappyState = false; // legit private property, no extra wacky syntax. Just JavaScript function closures.
// just return React component object
return {
state: { happy: props.initialHappyState }, // basically like public class fields, except no special syntax
onButtonClick: function onButtonClick() {
// no worries about binding this or using public class fields, because you're not using `this`!
if (canChangeHappyState) {
instance.setState({ happy: !instance.state.happy });
}
},
componentDidMount: function componentDidMount() {
// Real component lifecycle methods! They all work!
setTimeout(function () {
canChangeHappyState = true;
}, 5000);
},
render: function render() {
// access to state, props, and context just like from `this`
// except it's from the `instance`
var happy = instance.state.happy;
var clicks = instance.props.clicks;
var color = instance.context.color;
return _react2.default.createElement(
'div',
null,
_react2.default.createElement(
'div',
{ style: { width: 350 } },
'Cannot change happy state for the first 5 seconds due to a genuine private ',
_react2.default.createElement(
'code',
null,
'canChangeHappyState'
),
' variable, which is: ',
(0, _stringify2.default)(canChangeHappyState)
),
_react2.default.createElement(
'button',
{ onClick: instance.onButtonClick },
'instance.state.happy: ',
happy ? ':-)' : ':-('
),
_react2.default.createElement(
'div',
null,
'instance.props.clicks: ',
clicks
),
_react2.default.createElement(
'div',
{ style: { color: color } },
'instance.context.color: ',
color
)
);
}
};
}, { // static properties go here :)
defaultProps: { initialHappyState: true },
propTypes: { initialHappyState: _react2.default.PropTypes.bool },
contextTypes: { color: _react2.default.PropTypes.string }
});
var root = _react2.default.createElement(
StateSetterWithColorContext,
{ initialState: { clicks: 0 } },
function (_ref, setState) {
var clicks = _ref.clicks;
return _react2.default.createElement(
'div',
{ style: { margin: 70 } },
_react2.default.createElement(
'div',
{ style: { marginRight: 20 } },
_react2.default.createElement(
'button',
{ onClick: function onClick() {
return setState({ clicks: clicks + 1 });
} },
'click me'
),
_react2.default.createElement(SmileyFace, { clicks: clicks }),
_react2.default.createElement(
'div',
{ style: { width: 400, marginTop: 50 } },
'Just experimenting for fun. Please spare me the "what about perf?" and "I don\'t like this" and "this isn\'t really better" or "yeah, duh!" yada yada. I\'m just a programmer having some fun... But I think it\'s neat! Creating components via the module pattern! Private members are easy and obvious. State, props, and context all without using `this` or classes. Lifecycle methods work too. All from 10 lines of code :)'
)
)
);
}
);
_reactDom2.default.render(root, document.getElementById('root'));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment