preact pubnub twitter firehose

by Kye Hohenberger

HTML

<script src="https://unpkg.com/preact"></script>
<script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.4.4.min.js"></script>

SCSS

html, body {
	background: #EEE;
	margin: 0;
	font: 16px/1.3 'Helvetica Neue', helvetica, arial, sans-serif;
	color: #000;
}

.count {
	position: fixed;
	right: 0;
	top: 0;
	padding: 10px;
	background: #000;
	color: #FFF;
	z-index: 100;
}

.item {
	position: relative;
	box-sizing: border-box;
	padding: 10px;
	width: 100%;
	height: 90px;
	background: #FFF;
	border-bottom: 1px solid #DDD;
	overflow: hidden;
	contain: strict;
}

.avatar {
	float: left;
	margin: 0 10px 0 0;
	width: 48px;
	height: 48px;
	img {
		width: 48px;
		height: 48px;
		border-radius: 3px;
	}
}

.author-name {
	color: #555;
	text-decoration: none;
	font-weight: bold;
}

.author-screenname {
	color: #AAA;
	margin-left: 1em;
	text-decoration: none;
	font-size: 80%;
}

.text {
	margin: 0;
	padding: 0;
	overflow: hidden;
}

Babel + JSX

const { h, Component, render } = preact; /** @jsx h */

/**	Demo: Stream twitter firehose into
 *	a naive VDOM list with shouldComponentUpdate.
 */

class Demo extends Component {
	state = {
		messages: []
	};

	handleMessage = msg => {
		// we'll mutate in-place to save some copy ops
		// TIP: you can store VDOM in state!
		// Avoids constantly re-mapping data -> VDOM in render.
		this.state.messages.push(
			<Message id={msg.message.id_str} message={msg.message} />
		);
		// just trigger a state update
		this.setState();
	};

	componentDidMount() {
		let stream = new PubNub({
			subscribeKey: 'sub-c-78806dd4-42a6-11e4-aed8-02ee2ddab7fe'
		});
		stream.addListener({
			message: this.handleMessage
		});
		stream.subscribe({
			channels: ['pubnub-twitter']
		});
	}

	render({ }, { messages }) {
		return (
			<div class="list">
				<span class="count">{messages.length} tweets ({messages.length*9} elements)</span>
				{messages}
			</div>
		);
	}
}

class Message extends Component {
	shouldComponentUpdate(nextProps) {
		return nextProps.id!==this.props.id;
	}
	render({ message }) {
		let profileUrl = 'https://twitter.com/'+message.user.screen_name;
		return (
			<div class="item">
				<a class="avatar" href={profileUrl} target="_blank">
					<img src={message.user.profile_image_url_https} />
				</a>
				<a class="author-name" href={profileUrl} target="_blank">
					{message.user.name}
				</a>
				<a class="author-screenname" href={profileUrl} target="_blank">
					@{message.user.screen_name}
				</a>
				<p class="text">{message.text}</p>
			</div>
		);
	}
}

render(<Demo />, document.body);