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

@marudor/redux-prefetch

v0.2.2

Published

prefetch async state on the server for universal react apps built with redux

Downloads

5

Readme

Redux prefetch

Allows universal server-side rendering to be performed without much hassle. Exposes @fetch decorator and storeEnchancer, which keeps track of unresolved promises. Add .resolve function to store

Install

npm i redux-prefetch -S

Usage

The most important files are listed here, but look in the example for some extra stuff.

// createStore.js
import { createStore, applyMiddleware, compose } from 'redux';
import promiseMiddleware from 'redux-promise-middleware';
import reducers from '../modules/reducers';
import { syncReduxAndRouter } from 'redux-simple-router';
import { canUseDOM as isBrowser } from 'fbjs/lib/ExecutionEnvironment';
import { reduxPrefetch } from 'redux-prefetch';

export default function returnStore(history, initialState) {
  const middleware = [promiseMiddleware()];

  let finalCreateStore;
  if (isBrowser) {
    finalCreateStore = applyMiddleware(...middleware);
  } else {
    finalCreateStore = compose(reduxPrefetch, applyMiddleware(...middleware));
  }

  const store = finalCreateStore(createStore)(reducers, initialState);
  syncReduxAndRouter(history, store);

  return store;
}
// server.js
import React from 'react';
import merge from 'lodash/object/merge';
import { renderToString, renderToStaticMarkup } from 'react-dom/server';
import { match, RoutingContext } from 'react-router';
import routes from './routes';
import createStore from './store/create';
import metaState from './constants/config.js';
import HTML from './components/HTML';
import { Provider } from 'react-redux';
import serialize from 'serialize-javascript';
import DocumentMeta from 'react-document-meta';

export default function middleware(config = {}) {
  const meta = merge({}, metaState, config);

  // this is middleware for Restify, but can easily be changed for express or similar
  return function serveRoute(req, res, next) {
    match({ routes, location: req.url }, (err, redirectLocation, renderProps) => {
      if (err) {
        return next(err);
      }

      if (redirectLocation) {
        res.setHeader('Location', redirectLocation.pathname + redirectLocation.search);
        res.send(302);
        return next(false);
      }

      if (!renderProps) {
        return next('route');
      }

      // this is because we don't want to initialize another history store
      // but apparently react-router passes (err, state) instead of (state), which
      // is expected by redux-simple-router
      const { history } = renderProps;
      const { listen: _listen } = history;
      history.listen = callback => {
        return _listen.call(history, (_, nextState) => {
          return callback(nextState.location);
        });
      };
      const store = createStore(history, { meta });

      // wait for the async state to resolve
      store.resolve(renderProps.components, renderProps.params).then(() => {
        const page = renderToString(
          <Provider store={store}>
            <RoutingContext {...renderProps} />
          </Provider>
        );
        const state = store.getState();
        const exposed = 'window.__APP_STATE__=' + serialize(state) + ';';
        const html = renderToStaticMarkup(<HTML meta={DocumentMeta.renderAsHTML()} markup={page} version="0.14.3" state={exposed} />);

        res.setHeader('content-type', 'text/html');
        res.send(200, '<!DOCTYPE html>' + html);
        return next(false);
      });
    });
  };
}
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import DocumentMeta from 'react-document-meta';
import { dummy } from './modules/user' ;
import { fetch } from 'redux-prefetch';

function prefetch({ dispatch, getState }, params) {
  const timeout = parseInt(params.id || 30, 10);
  if (getState().user.result !== timeout) {
    return dispatch(dummy(timeout));
  }
}

// this is the important part
// it wraps the component with 2 handlers: componentDidMount() and static fetch()
// static function is performed on the server for state resolution before rendering
// the data
// componentDidMount() is obviously only performed on the client. Because this state
// will be already resolved on load, you need to make sure that necessary checks are performed
// and async actions are not repeated again
@fetch("root", prefetch)
@connect(state => ({ meta: state.meta, user: state.user }))
export default class App extends Component {
  static propTypes = {
    children: PropTypes.element,
    meta: PropTypes.object.isRequired,
    user: PropTypes.object.isRequired,
  };

  static contextTypes = {
    store: PropTypes.object.isRequired,
  };

  render() {
    return (
      <div>
        <DocumentMeta {...this.props.meta.app} />
        <h1>Hello world: {this.props.user.result}</h1>
        <div>{this.props.children && React.cloneElement(this.props.children, {
          userId: this.props.user.result,
        })}</div>
      </div>
    );
  }
}