Crawlable, component and events based, easy to mantain CouchApps using Facebook's React.js to render the same HTML inside CouchDB's _list and _show and then easily update or re-render them at client side using the same libraries, the same components.
Attention: this is an old project, so it uses an old React version, but since it is only an example of how to structure your Couchapp with React, then it still has value as that. The source code is commented everywhere and there are various README.md pages explaining how and why things work.
Reactive Couch is a bunch of patterns for declaring React components, rendering them inside _list and _show functions and binding the components with javascript them to the rendered HTML elements at the rendered app/website.
To achieve this we need:
- A single page HTML template -- all elements which will be targets of components must be present at the same page;
- Various components, each with different concerns -- with _list and _show we can render only one kind of data at once, each data must be tied to a component, and each component to a different HTML element;
- An event emitter for communication between components -- this is not the only way of communication, but we found it to be a good, simple and clean way of achieving this.
- A history plug (you can call it a router, but it is not exactly) to change the URL, while the visitor navigates using only client-side javascript and ajax, to a path with which the server can render the same page at a later visit.
For reasons of preference, in this project we also use:
- Coffeescript -- with the known lispy syntax for declaring React tags;
- Erica for pushing the directory files to CouchDB as a design document; and
- curljs for requering in the browser the same modules we require with CommonJS syntax at the server.
- a Makefile for compiling Coffeescript, syncing directories and pushing the design doc to CouchDB (a system that can be replaced by other tools, but very simple and in which anyone can plug in easily things like a JSX or a Less compilers, or a minifier)
Everything is included in this package, but you can probably remove and change everything easily.
If you're working with CouchDB, you probably already thinks in terms of documents and rows of _views, so the data for your page/app is probably structured in a way that you can clearly see that
- some kinds of data can be represented as a list of docs or rows of emitted data from one or more docs;
- some kinds of data can be represented as a single doc, and then it is all inside a doc.
So, this is the first step of structuring a Reactive Couch project: thinking about your data.
After you acknowledge these points and identify the data you will display, your next step is to proceed to the views
folder of the reactive couch project. There you you edit and create the view functions you'll need for displaying the data of kind 1.
Then you move to the lists
folder. There you'll find an example of a list function that just fetches the rows emitted from some passed view and provides
then as 'html'
and as 'json'
. You can edit the behavior of the fetch()
function, but the crucial part is that both the HTML and the JSON providers must have the same data. The tpl = require 'app/template'
and tpl @app.app, data
parts of the HTML provider are meant to render the data to the same HTML template, which is defined at https://github.com/fiatjaf/reactive-couch/blob/master/app/template.coffee.
Repeat the last step for data of kind 2, only that now you'll work with functions receiving single docs inside the shows
folder.
Inside the shows
folder there's also an index.coffee. This is a not necessary, but recommended, form of redirecting the user from the top level path of your website to a more meaninful URL pointing to the actual data at the home page -- and it is also useful for passing parameters the ever-needed parameters such as include_docs=true
to CouchDB.
Now, the React moment: move to the components
folder. There you'll find some components, each one in its file, no one of these are required, there are some (like RangeField
or RadioField
written by me that are included only as examples). Just pay attention to ListComponent
and Thing
, because these implement the logic for rendering the same thing server-side and client side, each assuming that will receive data as props -- if they're being rendered server-side --, or no data -- if not. In the second case they probably should be rendered with a style="display: none"
or some other pattern for showing/hiding elements in single pages or some fallback for inexistence of data, such as a "loading" message. There are comments inside these files explaining its important parts, ListComponent
is a components meant to be populated with list data, and Thing
with a single doc.
It is important to maintain the UMD-inspired syntax of the components, with the dependencies defined at deps
at the top, the component itself being returned by a factory
:
deps = ['lib/react']
factory = (React) ->
# component definition
and the last 4 lines:
if typeof define == 'function' and define.amd
define deps, factory
else if typeof exports == 'object'
module.exports = factory.apply @, deps.map require
The components defined at the previous step will now be binded to HMTL elements. At app/template there is, as a string, the full base template of the page your website will have. For each of your top-level components (the ones meant to be populated with _list or _show data), instantiate a div
(or similar) and call React.renderComponentToString
inside it, with data
as argument (data
will be populated inside each _list/_show function with the correct data). browsercode
is the other element of the mixture, it is the browser-only code, defined at app/app as plain javascript. It is mainly the curljs config, instantiation of the global window.ee
, the event emitter and binding of the React components to the same divs into which we called React.renderComponentToString
(they must be properly identified by ids to facilitate this process).
rewrites.json is used to give prettier and easy URL syntax for CouchDB. Edit the first two lines, add more lines as you add more components, read about it at the wiki, but there is nothing much to do here.
Everything is ready. just run make
.
- When you run
make
the contents of thelib
folder andcomponents
folder will be copied to the homonymous folders inside\_attachments
, so you don't need to modify these directly, everything will be copied and everything will be available at the server and at the browser. - Modules at the
lib
should have to be AMD and CommonJS compatible. If they are not, you have to modify then and trick CouchDB and curljs into thinking they are. Read about it at https://github.com/umdjs/umd and https://github.com/cujojs/curl/wiki/js#wiki-the-js-plugin.