1.0.0 • Published 5 years ago

connect-initial-props v1.0.0

Weekly downloads
64
License
MIT
Repository
github
Last release
5 years ago

connect-initial-props

A decorator for Next.js and React-Redux apps to connect getInitialProps to state and dispatch.

Why?

When using react-redux on a Next.js project, the static getInitialProps method is executed before react-redux's had been able to map state and dispatch to props.

The result is that accessing the dispatching actions or later accessing the state in getInitialProps is complicated.

Using this decorator you will be able to access mapped state and dispatch actions just as you would access them in a non-static method.

Example

Without connect-initial-props:

static async getInitialProps(ctx) {
  const { store, query, res } = ctx;
  await store.dispatch(getItems({ page }));

  const { totalPages } = mapStateToProps(store.getState());

  if (page <= 1 || page > totalPages) {
    res.redirect(301, '/?page=1');
    return {};
  }

  return { page };
}

With connect-initial-props's help:

@connectInitialProps(mapStateToProps, mapDispatchToProps)
static async getInitialProps(ctx, props) {
  const { res } = ctx;
  const { page, getItems } = props;

  // async call to load items from api
  await getItems({ page });

  // props got updated with up-to-date state after async request
  const { totalPages } = props;

  if (page <= 1 || page > totalPages) {
    res.redirect(301, '/?page=1');
    return {};
  }
}

Full Component Example

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import connectInitialProps from 'connect-initial-props';
import { createStructuredSelector } from 'reselect';
import { selectItems, selectTotalPages } from './selectors';
import { getItems } from './slice';

const mapStateToProps = createStructuredSelector({
  items: selectItems,
  totalPages: selectTotalPages
});

const mapDispatchToProps = { getItems };

@connect(mapStateToProps, mapDispatchToProps)
class Example extends Component {
  static propTypes = {
    items: PropTypes.array.isRequired,
    totalPages: PropTypes.number.isRequired
  };
+ @connectInitialProps(mapStateToProps, mapDispatchToProps)
-  static async getInitialProps(ctx) {
+  static async getInitialProps(ctx, props) {

     // We don't need store nor query anyore
-    const { store, query, res } = ctx;
+    const { res } = ctx;

+    const { page, getItems } = props;

     // No need to dispatch manually
-    await store.dispatch(getItems({ page }));
+    await getItems({ page });

     // No need provide store's state manually
-    const { totalPages } = mapStateToProps(store.getState());
+    const { totalPages } = props;

    if (page <= 1 || page > totalPages) {
      res.redirect(301, '/?page=1');
      return {};
    }
  }
  render() {
    const { page, totalPages, items } = this.props;

    return (
      <>
        <h1>
          Page {page} of {totalPages}
        </h1>
        {items.map(item => (
          <Item {...item} />
        ))}
      </>
    );
  }
}