Redux en Next.js

Instalar Redux

npm add -S redux react-redux next-redux-wrapper redux-devtools-extension redux-thunk

Configurar Redux en Next.js

  1. Añadimos el wrapper next-redux-wrapper al componente pages/_app.






 



 


 








 



 

 





 

// pages/_app

/* Vendor */

// React and Redux.
import React from 'react';
import { Provider } from 'react-redux';

// Next.
import App, { Container } from 'next/app';
import withRedux from 'next-redux-wrapper';

/* Redux Store */
import { makeStore } from 'store';

class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {};
    return { pageProps };
  }

  render() {
    const { Component, pageProps, store } = this.props;

    return (
      <Container>
        <Provider store={store}>
          <Component {...pageProps}/>
        </Provider>
      </Container>
    );
  }
}

export default withRedux(makeStore)(MyApp);

La función withRedux toma makeStore como primer argumento, y el resto de argumentos (opcionales) serán pasados a la función react-redux-connect.

// src/store/index.js

/* Vendor */
import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';
import thunkMiddleware from 'redux-thunk';

/* Reducer */
import reducer, { exampleInitialState } from 'reducers';

const makeStore = (initialState = exampleInitialState) => createStore(
  reducer,
  initialState,
  composeWithDevTools(applyMiddleware(thunkMiddleware)),
);

export default makeStore;

La función makeStore recibirá el objeto initialState como primer argumento, que es el estado inicial que le pasa el servidor al cliente. Esta función retornará una nueva instancia de la Redux store.

// src/reducers/index.js

/* Action types */
import { actionTypes } from 'actions';

export const exampleInitialState = {
  lastUpdate: 0,
  light: false,
  count: 0,
};

export default (state = exampleInitialState, action) => {
  switch (action.type) {
    case actionTypes.TICK:
      return Object.assign({}, state, {
        lastUpdate: action.ts,
        light: !!action.light,
      });
    case actionTypes.ADD:
      return Object.assign({}, state, {
        count: state.count + 1,
      });
    default:
      return state;
  }
};
// src/actions/index.js

export const actionTypes = {
  ADD: 'ADD',
  TICK: 'TICK',
};

export const addCount = () => dispatch => {
  return dispatch({ type: actionTypes.ADD });
};

export const serverRenderClock = isServer => dispatch => {
  return dispatch({ type: actionTypes.TICK, light: !isServer, ts: Date.now() });
};

export const startClock = () => dispatch => {
  return setInterval(
    () => dispatch({ type: actionTypes.TICK, light: true, ts: Date.now() }),
    1000,
  );
};