npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-rethinkdb

v0.7.0

Published

RethinkDB ReactJS integration

Downloads

27

Readme

npm version Travis

react-rethinkdb

Render realtime RethinkDB results in React

Get started

To get started immediately, follow the examples/tutorial/ project, or clone some of the other projects in examples/.

What is this?

This library provides a React mixin for running RethinkDB queries in any React component directly from the browser. It wraps rethinkdb-websocket-client to connect to the database, and is intended to be used with rethinkdb-websocket-server running in the backend.

This is similar to solutions like Meteor, Parse, and Firebase. Rather than writing database queries in the backend and exposing API endpoints to the frontend, these solutions allow the frontend to directly access the data layer (secured by a permission system) using the same query API that backend services have access to.

| | React support | Database | Realtime | Open-source | | --------------- | ------------- | ----------- | ---------| ------------| | react-rethinkdb | ✓ | RethinkDB | ✓ | ✓ | | Meteor | react-meteor and react-packages | MongoDB | ✓ | ✓ | | Parse | ParseReact | MongoDB | | | | Firebase | ReactFire | MongoDB | ✓ | |

What is React?

React is a JavaScript library for building user interfaces. It's pretty cool.

This library only works with React by design. If you are interested in connecting to RethinkDB from the browser without React, you can use rethinkdb-websocket-client.

What is RethinkDB?

RethinkDB is an open-source NoSQL database with baked in realtime capabilities. It is quite popular, it is the second most starred database on GitHub after Redis.

Is this secure?

Although it seems quite insecure to run database queries directly from the frontend, all queries should be validated by rethinkdb-websocket-server before they are forwarded to RethinkDB. From its README:

As you are developing, incoming queries that don't validate against the whitelist will be logged to console in a format that you can copy and paste directly into your JavaScript source file. For dynamic queries, you'll likely want to generalize the pattern using RP.check() terms, RP.ref() terms, and the .validate() method.

See examples/chat/ for an example app that has user authentication and query validation in the backend.

Most of the query validation logic can be found in QueryValidator.js.

How do I use this?

Check out the examples/ folder in this repository for fully-working React applications. You will need to install RethinkDB version 2.2 or newer first if you haven't already.

The examples/tutorial/ project has in-depth instructions explaining how to create a simple app from scratch.

You can also peruse the comments in the source code in the src/ directory:

  • Session.js to create a new websocket connection to the backend/database
  • Mixin.js to enable a React component to subscribe to RethinkDB queries
  • QueryRequest.js to configure queries in subscribed React components
  • QueryResult.js to use results from queries in render()

Below is a very simple React application to give an idea of the syntax:

var React = require('react');
var ReactDOM = require('react-dom');
var ReactRethinkdb = require('react-rethinkdb');
var r = ReactRethinkdb.r;

ReactRethinkdb.DefaultSession.connect({
  host: 'localhost',          // hostname of the websocket server
  port: 8015,                 // port number of the websocket server
  path: '/',                  // HTTP path to websocket route
  secure: false,              // set true to use secure TLS websockets
  db: 'test',                 // default database, passed to rethinkdb.connect
  autoReconnectDelayMs: 2000, // when disconnected, millis to wait before reconnect
});

var App = React.createClass({
  mixins: [ReactRethinkdb.DefaultMixin],

  observe: function(props, state) {
    return {
      turtles: new ReactRethinkdb.QueryRequest({
        query: r.table('turtles'), // RethinkDB query
        changes: true,             // subscribe to realtime changefeed
        initial: [],               // return [] while loading
      }),
    };
  },

  handleSubmit: function(event) {
    event.preventDefault();
    var nameInput = this.refs.firstName;
    var query = r.table('turtles').insert({firstName: nameInput.value});
    nameInput.value = '';
    ReactRethinkdb.DefaultSession.runQuery(query);
  },

  render: function() {
    var turtleDivs = this.data.turtles.value().map(function(x) {
      return <div key={x.id}>{x.firstName}</div>;
    });
    return <div>
      <form onSubmit={this.handleSubmit}>
        <input type="text" ref="firstName" />
        <input type="submit" />
      </form>
      {turtleDivs}
    </div>;
  },
});

ReactDOM.render(<App />, document.getElementById('app'));

Features

  • Realtime queries with RethinkDB changefeed support
  • Share results of identical queries across React components

Limitations

  • RethinkDB changefeeds don't work on aggregations like .count(), but it will eventually be supported.
    • https://github.com/rethinkdb/rethinkdb/issues/3735
    • https://github.com/rethinkdb/rethinkdb/issues/1118
  • RethinkDB changefeed queries with .orderBy() may not be ordered correctly, but it will eventually be possible.
    • https://github.com/rethinkdb/rethinkdb/issues/3714

Compatibility

So far, this library has been tested successfully in the following environments:

  • Chrome 43 (Linux)
  • Chrome 43 (Android 5.0)
  • Chrome 43 (Android 4.4)
  • Chrome 44 (OS X 10.10)
  • Firefox 38 (Linux)
  • Safari 7.1 (OS X 10.9)
  • Safari 8.0 (OS X 10.10)
  • Safari 8.0 (iOS 8.1)
  • IE11 (Win 7)
  • IE10 (Win 7)
  • Node.js 0.12 (Linux)

In IE10, your queries must use r.bracket instead of function-call shorthand. E.g. r.table('turtles').get(id)("name") must be written as r.table('turtles').get(id).bracket("name"). See rethinkdb#162 for more details.

IE9 and old android browsers are not supported because they don't have WebSockets, and rethinkdb-websocket-client currently requires WebSocket support.

Upgrade guide

Most new versions of react-rethinkdb are backwards compatible with previous versions. Below are exceptions with breaking changes:

Upgrading to 0.5 (from 0.4)

Version 0.5 of react-rethinkdb saw the introduction of atomic changefeeds, which is a new feature in RethinkDB 2.2. This simplifies the logic by sending one "atomic" changefeed query, rather than a static query for initial results followed by a changefeed query for realtime updates. This saves bandwidth and prevents the race condition where data changes in between the two queries.

Regular static queries will continue to work the same. But in order to use react-rethinkdb 0.5 with changefeed queries, you must both:

  • Upgrade to RethinkDB 2.2 in your backend.
  • Add the include_initial=true option to all changefeed queries in your rethinkdb-websocket-server query whitelist. Below is an example:
r.table("tortoises")
 .changes({
   includeStates: true,
   includeInitial: true, // this line is now required
 })
 .opt("db", r.db("test")),

Or with the old syntax:

RQ(
  RQ.CHANGES(
    RQ.TABLE("tortoises")
  ).opt("include_states", true)
   .opt("include_initial", true) // this line is now required
).opt("db", RQ.DB("test")),

Roadmap

  • Investigate performance. I haven't tested with large queries, large numbers of queries, or large result sets.
  • Change mixin API when best practices are established for data loading in React.
    • https://github.com/facebook/react/issues/3398
    • https://github.com/facebook/react/issues/3858
    • https://github.com/facebook/react/pull/3920
  • Support for React components written as ES6 classes
  • React Native support (currently completely untested)
  • Isomorphic app support (currently incomplete)
    • This might be tricky for queries with changefeeds unless we require the browser to rerun the query. But then we might have an extra loading flicker
    • To use on the server in node.js (as opposed to the browser), use the following path when importing the module: var ReactRethinkdb = require('react-rethinkdb/dist/node');
    • See the examples/isomorphic/ directory for example usage
  • Query result caching
    • If a component subscribed to a query is unmounted, and a component is later mounted with the same exact query, the second component should optionally be able to display the cached results.
    • In SubscriptionManager.js, when a component is the last to unsubscribe from a query, instead of removing the query state, we would just close the query but keep the state around (marked as stale) in case another component later subscribes. We may even set a timer before closing the query and marking it stale in case it's common for components to quickly resubscribe.
    • Components may specify if they are fine with stale results or if they need a refresh.
    • We will need an invalidation policy so we don't leak memory.
  • Optimistic updates (equivalent to Meteor's latency compensation)