vnext Widgets: Bootstrapping
by Troy Rhinehart
why
how
why
-
ReactDOMServer
-
Dynamic Content
-
Minimal Client JS
why
ReactDOMServeR
class App extends React.Component {
handleClick = (e) => {
console.log(e);
};
render() {
return (
<h1 onClick={ this.handleClick }>
Hello World
</h1>
);
}
}
<h1
data-reactroot=""
data-reactid="1"
data-react-checksum="55251490"
>
Hello World
</h1> ReactDOMServer.renderToString(<App/>);why
DYNAMIC CONTENT
- interactions
- external resources
- state validation
why
Minimal Client Resources
- no stores
- no context
- return null
how
-
props/context
-
webpack RAW-LOADER
-
Return null
HOW
PROPS/CONTEXT
import React from 'react';
import PropTypes from 'prop-types';
import { components } from '@wsb/guac-widget-core';
import Component from './Component';
import rawComponent from 'webpack-raw!./raw';
const { Bootstrap } = components;
export default function Bootstrapped(props) {
return (
<Bootstrap
{...props}
Component={ Component }
rawComponentScript={ rawComponent }
exportedComponent={ 'Bootstrapped' }
/>
);
}
BootstrappedComponent.propTypes = {
renderMode: PropTypes.string.isRequired
}; <Script children={ [
rawComponentScript,
`(function() {
var props = ${JSON.stringify(widgetProps)};
var context = ${JSON.stringify(contextProps)};
if (context.theme) {
context.theme = window.wsb[context.theme];
}
ReactDOM.render(
React.createElement(
Core.UX2.Base,
context,
React.createElement(
window.wsb['${exportedComponent}'],
props
)
),
document.getElementById('${domTargetId}')
);
})();`
] }/>HOW
WEBPACK RAW-LOADER
- externals
- React/ReactDOM
- Lodash
- Immutable
- minified/uglified
- commonjs
- webpack-null-loader
HOW
RETURN NULL - before
<div>
<ScrollToButton
target="#target"
children="Click Me - Button"
/>
<ScrollToLink
target="#target"
children="Click Me - Link"
/>
<ScrollToImage
target="#target"
src="//img.com"
/>
<ScrollToBackground
target="#target"
backgroundImage="//img.com"
/>
...
<div id="target">...</div>
</div>HOW
RETURN NULL - AFTER
<div>
<ScrollTo target="#target">
<UX2.Element.Button>Click Me - Button</UX2.Element.Button>
</ScrollTo>
<ScrollTo target="#target">
<UX2.Element.Link>Click Me - Link</UX2.Element.Link>
</ScrollTo>
<ScrollTo target="#target">
<UX2.Element.Image src="//img.com"/>
</ScrollTo>
<ScrollTo target="#target">
<UX2.Element.Background
backgroundImage="//img.com"
/>
</ScrollTo>
...
<div id="target">...</div>
</div>HOW
RETURN NULL - BOOTSTRAP
class ScrollTo extends React.Component {
constructor() {
super(...arguments);
this.id = _.uniqueId('scroll-to');
}
render() {
const { target, children, ...props } = this.props;
return (
<UX2.Element { ...props } id={ this.id }>
{ React.Children.only(children) }
<Bootstrap
target={ target }
subject={ `${this.id} > :first-child` }
Component={ ScrollToComponent }
rawComponentScript={ rawComponent }
exportedComponent={ 'ScrollTo' }
/>
</UX2.Element>
);
}
}HOW
RETURN NULL - Component
class ScrollToComponent extends React.Component {
handleClick = (e) => {
// scrollTo logic using this.props.target
};
componentDidMount() {
this.subject = document.querySelector(this.props.subject);
this.subject && this.subject.addEventListener('click', this.handleClick);
}
componentWillUnmount() {
this.subject && this.subject.removeEventListener('click', this.handleClick);
}
render() {
return null;
}
}Questions?
Widget Bootstrapping
By gingur
Widget Bootstrapping
Slides for tech talk related to the do's/don'ts on widget bootstrapping for published websites
- 197