react-server-data is a simple API to allow pushing asynchronous data (database, network, file access, etc) from a Server Side Rendered React app to the browser. It is designed to easily slot into existing apps and to support the new server React.Suspense asynchronous rendering when it is made available.

It does this by registering "action" promises to run. Components declare what actions they will need in the render method, and then react-server-data loads all of them before the final HTML page is sent. This can also allow HTML head tags to be populated without relying on a library like react-helmet (which has asynchronous problems)

React-server-data is not a perfect solution, the current limitations means it cannot prepopulate the page from the server side (this will require the new server side React.Suspense). Suspense and hooks are going to be supported as soon as they are officially available in React.

Setup

Actions must be setup at the start on both the Client and Server. Server actions can talk directly to the database or API endpoint, while clients will look closer to traditional fetch/AJAX requests.

Server Side

import { ServerDataStore } from " react-server-data " ; ServerDataStore . registerAction ( " blogs " , ( ... options ) => { return db . getBlogs ( ... options ) ; } ) ;

Client Side

import { ServerDataStore } from " react-server-data " ; ServerDataStore . registerAction ( " blogs " , ( ... options ) => { return fetch ( " https://api.com/blogs " ) ; } ) ;

After registering actions, you can pass down the ServerDataContext when you SSR

import { ServerDataContext , ServerDataStore } from " react-server-data " ; function onPageRender ( ) { const serverDataStore = new ServerDataStore ( ) ; const renderedString = renderToString ( < ServerDataContext . Provider value = { serverDataStore } > < BlogPage / > < / ServerDataContext . Provider > ) ; const serverData = await serverDataStore . getDataAsString ( ) ; const tags = await serverDataStore . getTagsAsString ( ) ; return ` <!DOCTYPE html> <html> <head> ${ tags } ${ serverData } </head> <body> ${ renderedString } </body> </html> ` ; }

When a component that loads data renders, it must use runAction to begin running an action, this can either be done with a context Consumer or using the static contextType.

In the future this will be much easier to do with react-hooks and React.useContext

import { ServerDataContext , ServerDataStore } from " react-server-data " ; class BlogPage extends React . PureComponent { constructor ( props ) { super ( props ) ; this . state = { blogs : [ ] } ; } async componentDidMount ( ) { const data = await ServerDataStore . getResult ( " blogs " , ... optional ) ; this . setState ( { blogs : data . data . blogs } ) ; } render ( ) { return ( < > < ServerDataContext . Consumer > { ( store ) => { store . runAction ( " blogs " , ... optional ) ; } } < / ServerDataContext . Consumer > { this . state . blogs && < > { } < / > } < / > ) ; } } class BlogPage extends React . PureComponent { static contextType = ServerDataContext ; constructor ( props ) { super ( props ) ; this . state = { blogs : [ ] } ; } async componentDidMount ( ) { const data = await ServerDataStore . getResult ( " blogs " , ... optional ) ; this . setState ( { blogs : data . data . blogs } ) ; } render ( ) { this . context . runAction ( " blogs " , ... optional ) ; return ( < > { this . state . blogs && < > { } < / > } < / > ) ; } }

Can also push meta tags out by using ServerDataTag