getting started feature roadmap faq
use cases pricing
developers
company
enterprise contact

Getting started with deepstreamHub is easy and takes less than ten minutes. However, if you have any questions, please get in touch.

This is a React Native guide that will take you through deepstreamHub's three core concepts: Records, Events and RPCs.

react-native CLI tool will assist you to scaffold a new React Native app easily and we'll use the JavaScript client SDK to interact with deepstreamHub.

Create a free account and get your API key

Create a React Native App

Install react-native globally and use the tool to scaffold a new app:

# Install create-react-app
npm install -g react-native-cli
# Scaffold new app
react-native DsReactNative

You will also need to setup the environement you are building for on your machine.

Connect to deepstreamHub and log in

Install the JS library to the DsReactNative app you just created:

# With yarn
yarn add deepstream.io-client-js
# With npm
npm install deepstream.io-client-js --save

Get your app url from the dashboard and establish a connection to deepstreamHub and login (we'll not configure any authentication, because there are no credentials required):

// ./index.ios.js
import createDeepstream from 'deepstream.io-client-js';
import React, { Component } from 'react';

export default class DsReactNative extends Component {
  constructor(props) {
    super(props);
    this.state = {};
    // Connect to deepstream
    this.ds = createDeepstream('<YOUR APP URL>');
    // Login
    this.client = this.ds.login();
  }  
}

export default App;

No surprises here. React Native is built on top of React, therefore most of the concepts you know from React are here.

Records (realtime datastore)

Records are the documents in deepstreamHub’s realtime datastore. A record is identified by a unique id and can contain any kind of JSON data. Clients and backend processes can create, read, write, update and observe the entire record as well as paths within it. Any change is immediately synchronized amongst all connected subscribers.

Records can be arranged in lists and collections and can contain references to other records to allow for the modelling of relational data structures.

You can learn more about records in the records tutorial.

Creating a new record or retrieving an existent one works the same way:

var myRecord = ds.record.getRecord( 'test/johndoe' );

Values can be stored using the .set() method:

myRecord.set({
    firstname: 'John',
    lastname: 'Doe'
});

Let's set up two-way bindings with an input field - whenever a path within our record, e.g. firstname changes we want to update the input. Whenever a user types, we want to update the record.

Two-way realtime bindings

First, we setup the record and subscribe for changes in the constructor:

// ./components/record.ios.js
// . . .
import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  TextInput,
  Text,
  View
} from 'react-native';
import {styles} from '../styles';

export class Record extends Component {
    constructor(props) {
        super(props);
        this.state = {
            firstname: '',
            lastname: ''
        };

        // Receive record from parent component
        // <Record record={this.client.record}></Record>
        this.record = this.props.record;

        // Bind handleChange methods to the right 'this'
        this.handleFnameChange = this.handleFnameChange.bind(this);
        this.handleLnameChange = this.handleLnameChange.bind(this);

        this.record.subscribe(value => {
            // Update state on input change
            this.setState({firstname: value.firstname});
            this.setState({lastname: value.lastname});
        });
    }
}

then we create the render method for the template which includes the TextInput fields:

// . . .
class Record extends Component {
    // . . .
    render() {
        return(
            <View style={{paddingTop: 30}}>
                <Text style={styles.h2}>Realtime Datastore</Text>
                <View>
                    <Text>Firstname</Text>
                    <TextInput 
                        style={styles.text}
                        value={this.state.firstname} 
                        onChangeText={this.handleFnameChange} />
                </View>
                <View style=>
                    <Text>Lastname</Text>
                    <TextInput 
                        style={styles.text}
                        value={this.state.lastname} 
                        onChangeText={this.handleLnameChange} />
                </View>
            </View>
        );
    }
}

and finally, we add the handleFnameChange and handleLnameChange method to sync the input fields state:

class Record extends Component {
    // . . .
     handleFnameChange(text) {
        this.setState({firstname: text});
        this.record.set('firstname', text);
    }

    handleLnameChange(text) {
        this.setState({lastname: text});
        this.record.set('lastname', text);
    }
 //. . .
}

Events (publish-subscribe)

Events are deepstreamHub’s publish-subscribe mechanism. Clients and backend processes can subscribe to event-names (sometimes also called “topics” or “channels”) and receive messages published by other endpoints.

Events are non-persistent, one-off messages. For persistent data, please use records.

Publish-Subscribe

Clients and backend processes can receive events using .subscribe():

constructor() {
    const dataSource = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
    this.state = {
        value: '',
        eventsDataSource: dataSource.cloneWithRows([]), 
        eventsReceived: []
    };
    // Receive event object from parent container, App.
    // <Event event={this.client.event}></Event>
    this.event = this.props.event;
    this.handlePress = this.handlePress.bind(this);
    this.handleChange = this.handleChange.bind(this);

    this.event.subscribe('event-data', data => {
        this.setState(
            {
                    eventsReceived: [...this.state.eventsReceived, data]
            }, (prevState, props) => {
                this.setState({eventsDataSource: dataSource.cloneWithRows([...this.state.eventsReceived])})
                this.setState({value: ''});
            })
    });
}

... and publish events using .emit():

handlePress(text) {
    this.event.emit('event-data', text);
}

This is what your handleChange and render method should look like:

handleChange(text) {
    this.setState({value: text});
}
r
ender() {
    return(
        <View>
            <View>
                <Text style={styles.h2}>Publish</Text>
                <TextInput 
                    placeholder="Event data..."
                    style={styles.text} 
                    value={this.state.value} 
                    onChangeText={this.handleChange} />
                <Button onPress={this.handlePress} title="Send" color="#841584" />
            </View>
            <View>
                <Text style={styles.h3}>Subscriptions</Text>
                <ListView
                    dataSource={this.state.eventsReceived}
                    enableEmptySections={true}
                    renderRow={(rowData) => <Text>Received event data: {rowData}</Text>}
                    />
            </View>
        </View>
    );
}

RPCs (request-response)

Remote Procedure Calls are deepstreamHub’s request-response mechanism. Clients and backend processes can register as “providers” for a given RPC, identified by a unique name. Other endpoints can request said RPC.

deepstreamHub will route requests to the right provider, load-balance between multiple providers for the same RPC, and handle data-serialisation and transport.

Request Response

You can make a request using .make():

handlePress(e) {
        // read the value from the TextInput field
        // and convert it into a number
        var data = {
            value: parseFloat(this.state.requestValue)
        };

        // Make a request for `multiply-number` with our data object
        // and wait for the response
        this.rpc.make('multiply-number', data, function( err, resp ){

            //display the response (or an error)
            this.setState({displayResponse: resp || err.toString()});
        }.bind(this));
    }

and answer using .provide():

constructor() {
    // Receive rpc object from parent container, App
    // <RPC rpc={this.client.rpc}></RPC>
    this.rpc = this.props.rpc;
    this.rpc.provide( 'multiply-numbers', ( data, response ) => {
        response.send( data.a * data.b );
    });
}

Where to go next?

To learn how to use deepstreamHub with any other frontend frameworks, head over to the tutorial section. To learn how to use the JavaScript SDK with NodeJS rather than in a browser, head over to the getting started with NodeJS tutorial.

Resources

  • REPO: https://github.com/deepstreamIO/getting-started-react-native