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-server-data

v1.0.7

Published

Server side data loading for React

Downloads

11

Readme

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.

example

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); // Some asynchronous method
});

Client Side

import { ServerDataStore } from "react-server-data";
ServerDataStore.registerAction("blogs", (...options) => {
    // This is only run if the server never sent any data (for example, when navigating in a SPA)
    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";

/** Server render */
function onPageRender() {
    // Create a context store for this request
    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(){
        // If the server already ran this action, getResult will load that instead of doing a fetch request
        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 &&
                    <>
                    {/** Render the blogs here */}
                    </>
                }
            </>
        );
    }
}

/** Optionally you can use the static contextType instead */
class BlogPage extends React.PureComponent {
    static contextType = ServerDataContext;
    constructor(props) {
        super(props);
        this.state = { blogs: [] };
    }

    async componentDidMount(){
        // If the server already ran this action, getResult will load that instead of doing a fetch request
        const data = await ServerDataStore.getResult("blogs", ...optional);
        this.setState({ blogs: data.data.blogs });
    }

    render() {
        this.context.runAction("blogs", ...optional);
        return (
            <>
                {this.state.blogs &&
                    <>
                    {/** Render the blogs here */}
                    </>
                }
            </>
        );
    }
}

Can also push meta tags out by using ServerDataTag

import { ServerDataTag } from "react-server-data";

function BlogPage(){
    return (
        <>
            <ServerDataTag action="blog" args={[...options]}>
                {(blog) =>
                    <>
                        <title>{blog.title}</title>
                        <meta name="description" content={blog.short_description} />
                        <meta property="og:title" content={blog.title} />
                        <meta property="og:description" content={blog.short_description} />
                    </>
                }
            </ServerDataTag>
            // Rest of the page as normal
        </>
    );
}