preact composition demo 1
by Jason Miller
HTML
<script src="https://unpkg.com/preact/dist/preact.min.js"></script>
CSS
body {
font: 14px/1.21 'helvetica neue',helvetica,arial,sans-serif;
background: #fff;
}
Babel + JSX
const { h, cloneElement, Component, render } = preact; /** @jsx h */
/** Example <Fetch url="/foo" /> compositional component.
* Just to demonstrate a compositional component that requires input massaging.
*/
class Fetch extends Component {
state = { loading: true };
componentDidMount() {
this.update();
}
componentDidUpdate(prevProps) {
if (this.props.url!==prevProps.url) {
this.update(); // fetch changed url
}
}
update() {
let { url, as='json' } = this.props;
this.setState({ loading:true, error:null });
fetch(url)
.then( r => r[as]() )
.then( data => this.setState({ loading:false, data }) )
.catch( error => this.setState({ loading:false, data:null, error }) );
}
render(props, state) {
// just pass all state to the child as props
return cloneElement(props.children[0], state);
}
}
/** "Smart" component, akin to a Controller.
* Typically arguments/props to this come from the URL.
*/
const ProfilePage = ({ id }) => (
<Fetch url={'//api.myjson.com/bins/'+encodeURIComponent(id)}>
<ProfileView you-could="pass default props here" />
</Fetch>
);
/** "Dumb" view component, analagous to a template */
const ProfileView = ({ loading, data, error }) => (
<div class="some-view" data-loading={loading}>
{ error && <ErrorBox error={error} /> }
{ data && (
<div class="profile">
<h1>{data.name}</h1>
<p>{data.bio}</p>
<a href={data.url} target="_blank">{data.urlName}</a>
</div>
) }
</div>
);
/** A "template partial" */
const ErrorBox = ({ error }) => (
<div class="error">
<h1>We have a problem!</h1>
<pre>{error.message}</pre>
</div>
);
// magic:
render(<ProfilePage id="yoxtb" />, document.body);