UNPKG

create-expo-cljs-app

Version:

Create a react native application with Expo and Shadow-CLJS!

358 lines (338 loc) 8.81 kB
/** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format */ 'use strict'; /* eslint-env browser */ const React = require('react'); const { Image, PixelRatio, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View, } = require('react-native'); const DEFAULT_WS_URL = 'ws://localhost:5555/'; const DEFAULT_HTTP_URL = 'http://localhost:5556/'; const WS_EVENTS = ['close', 'error', 'message', 'open']; const WS_STATES = [ /* 0 */ 'CONNECTING', /* 1 */ 'OPEN', /* 2 */ 'CLOSING', /* 3 */ 'CLOSED', ]; class Button extends React.Component { render(): React.Element<any> { const label = <Text style={styles.buttonLabel}>{this.props.label}</Text>; if (this.props.disabled) { return ( <View style={[styles.button, styles.disabledButton]}>{label}</View> ); } return ( <TouchableOpacity onPress={this.props.onPress} style={styles.button}> {label} </TouchableOpacity> ); } } class Row extends React.Component { render(): React.Element<any> { return ( <View style={styles.row}> <Text>{this.props.label}</Text> {this.props.value ? <Text>{this.props.value}</Text> : null} {this.props.children} </View> ); } } class WebSocketImage extends React.Component { ws: ?WebSocket = null; state: {blob: ?Blob} = {blob: null}; componentDidMount() { let ws = (this.ws = new WebSocket(this.props.url)); ws.binaryType = 'blob'; ws.onmessage = event => { if (event.data instanceof Blob) { const blob = event.data; if (this.state.blob) { this.state.blob.close(); } this.setState({blob}); } }; ws.onopen = event => { ws.send('getImage'); }; } componentUnmount() { if (this.state.blob) { this.state.blob.close(); } this.ws && this.ws.close(); } render() { if (!this.state.blob) { return <View />; } return ( <Image source={{uri: URL.createObjectURL(this.state.blob)}} style={{width: 50, height: 50}} /> ); } } function showValue(value) { if (value === undefined || value === null) { return '(no value)'; } if ( typeof ArrayBuffer !== 'undefined' && typeof Uint8Array !== 'undefined' && value instanceof ArrayBuffer ) { return `ArrayBuffer {${String(Array.from(new Uint8Array(value)))}}`; } return value; } type State = { url: string, httpUrl: string, fetchStatus: ?string, socket: ?WebSocket, socketState: ?number, lastSocketEvent: ?string, lastMessage: ?string | ?ArrayBuffer, outgoingMessage: string, }; class WebSocketExample extends React.Component<any, any, State> { state: State = { url: DEFAULT_WS_URL, httpUrl: DEFAULT_HTTP_URL, fetchStatus: null, socket: null, socketState: null, lastSocketEvent: null, lastMessage: null, outgoingMessage: '', }; _connect = () => { const socket = new WebSocket(this.state.url); WS_EVENTS.forEach(ev => socket.addEventListener(ev, this._onSocketEvent)); this.setState({ socket, socketState: socket.readyState, }); }; _disconnect = () => { if (!this.state.socket) { return; } this.state.socket.close(); }; _onSocketEvent = (event: MessageEvent) => { const state: any = { socketState: event.target.readyState, lastSocketEvent: event.type, }; if (event.type === 'message') { state.lastMessage = event.data; } this.setState(state); }; _sendText = () => { if (!this.state.socket) { return; } this.state.socket.send(this.state.outgoingMessage); this.setState({outgoingMessage: ''}); }; _sendHttp = () => { this.setState({ fetchStatus: 'fetching', }); fetch(this.state.httpUrl).then(response => { if (response.status >= 200 && response.status < 400) { this.setState({ fetchStatus: 'OK', }); } }); }; _sendBinary = () => { if ( !this.state.socket || typeof ArrayBuffer === 'undefined' || typeof Uint8Array === 'undefined' ) { return; } const {outgoingMessage} = this.state; const buffer = new Uint8Array(outgoingMessage.length); for (let i = 0; i < outgoingMessage.length; i++) { buffer[i] = outgoingMessage.charCodeAt(i); } this.state.socket.send(buffer); this.setState({outgoingMessage: ''}); }; render(): React.Element<any> { const socketState = WS_STATES[this.state.socketState || -1]; const canConnect = !this.state.socket || this.state.socket.readyState >= WebSocket.CLOSING; const canSend = socketState === 'OPEN'; return ( <ScrollView style={styles.container}> <View style={styles.note}> <Text>To start the WS test server:</Text> <Text style={styles.monospace}> ./RNTester/js/examples/WebSocket/websocket_test_server.js </Text> </View> <Row label="Current WebSocket state" value={showValue(socketState)} /> <Row label="Last WebSocket event" value={showValue(this.state.lastSocketEvent)} /> <Row label="Last message received" value={showValue(this.state.lastMessage)} /> <Row label="Last image received"> {canSend ? <WebSocketImage url={this.state.url} /> : null} </Row> <TextInput style={styles.textInput} autoCorrect={false} placeholder="Server URL..." onChangeText={url => this.setState({url})} value={this.state.url} /> <View style={styles.buttonRow}> <Button onPress={this._connect} label="Connect" disabled={!canConnect} /> <Button onPress={this._disconnect} label="Disconnect" disabled={canConnect} /> </View> <TextInput style={styles.textInput} autoCorrect={false} placeholder="Type message here..." onChangeText={outgoingMessage => this.setState({outgoingMessage})} value={this.state.outgoingMessage} /> <View style={styles.buttonRow}> <Button onPress={this._sendText} label="Send as text" disabled={!canSend} /> <Button onPress={this._sendBinary} label="Send as binary" disabled={!canSend} /> </View> <View style={styles.note}> <Text>To start the HTTP test server:</Text> <Text style={styles.monospace}> ./RNTester/js/examples/WebSocket/http_test_server.js </Text> </View> <TextInput style={styles.textInput} autoCorrect={false} placeholder="HTTP URL..." onChangeText={httpUrl => this.setState({httpUrl})} value={this.state.httpUrl} /> <View style={styles.buttonRow}> <Button onPress={this._sendHttp} label="Send HTTP request to set cookie" disabled={this.state.fetchStatus === 'fetching'} /> </View> <View style={styles.note}> <Text> {this.state.fetchStatus === 'OK' ? 'Done. Check your WS server console to see if the next WS requests include the cookie (should be "wstest=OK")' : '-'} </Text> </View> </ScrollView> ); } } const styles = StyleSheet.create({ container: { flex: 1, }, note: { padding: 8, margin: 4, backgroundColor: 'white', }, monospace: { fontFamily: 'courier', fontSize: 11, }, row: { height: 40, padding: 4, backgroundColor: 'white', flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', borderBottomWidth: 1 / PixelRatio.get(), borderColor: 'grey', }, button: { margin: 8, padding: 8, borderRadius: 4, backgroundColor: 'blue', alignSelf: 'center', }, disabledButton: { opacity: 0.5, }, buttonLabel: { color: 'white', }, buttonRow: { flexDirection: 'row', justifyContent: 'center', }, textInput: { height: 40, backgroundColor: 'white', margin: 8, padding: 8, }, }); exports.title = 'WebSocket'; exports.category = 'Basic'; exports.description = 'WebSocket API'; exports.examples = [ { title: 'Basic websocket', render(): React.Element<typeof WebSocketExample> { return <WebSocketExample />; }, }, ];