├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── pages ├── _app.jsx └── index.jsx └── redux ├── actions └── counterActions.js ├── reducers ├── counterReducer.js └── rootReducer.js └── store.js /.gitignore: -------------------------------------------------------------------------------- 1 | .next 2 | 3 | node_modules 4 | 5 | .idea 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Nextjs-React-Redux-Example 2 | 3 | A Simple Counter App made with next.js, react and redux. 4 | 5 | To run the app: 6 | 7 | ``` 8 | npm install 9 | npm run dev 10 | ``` 11 | 12 | [Detailed Explanation](https://dev.to/waqasabbasi/server-side-rendered-app-with-next-js-react-and-redux-38gf) 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello-next", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "dev": "next", 8 | "build": "next build", 9 | "start": "next start" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "next": "^9.1.7", 16 | "next-redux-wrapper": "^4.0.1", 17 | "react": "^16.12.0", 18 | "react-dom": "^16.12.0", 19 | "react-redux": "^7.1.3", 20 | "redux": "^4.0.5" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /pages/_app.jsx: -------------------------------------------------------------------------------- 1 | import App from 'next/app'; 2 | import {Provider} from 'react-redux'; 3 | import React from 'react'; 4 | import withRedux from "next-redux-wrapper"; 5 | import store from '../redux/store'; 6 | 7 | class MyApp extends App { 8 | 9 | static async getInitialProps({Component, ctx}) { 10 | const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {}; 11 | 12 | //Anything returned here can be accessed by the client 13 | return {pageProps: pageProps}; 14 | } 15 | 16 | render() { 17 | //Page props that were returned from 'getInitialProps' are stored in the props i.e. pageprops 18 | const {Component, pageProps, store} = this.props; 19 | 20 | return ( 21 | 22 | 23 | 24 | ); 25 | } 26 | } 27 | 28 | //makeStore function that returns a new store for every request 29 | const makeStore = () => store; 30 | 31 | //withRedux wrapper that passes the store to the App Component 32 | export default withRedux(makeStore)(MyApp); 33 | 34 | -------------------------------------------------------------------------------- /pages/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import {connect} from 'react-redux'; 3 | import {decrementCounter, incrementCounter} from '../redux/actions/counterActions'; 4 | 5 | class App extends React.Component { 6 | 7 | static getInitialProps({store}) {} 8 | 9 | constructor(props) { 10 | super(props); 11 | } 12 | 13 | render() { 14 | return ( 15 |
16 | 17 | 18 |

{this.props.counter}

19 |
20 | ); 21 | } 22 | } 23 | 24 | const mapStateToProps = state => ({ 25 | counter: state.counter.value 26 | }); 27 | 28 | const mapDispatchToProps = { 29 | incrementCounter: incrementCounter, 30 | decrementCounter: decrementCounter, 31 | }; 32 | export default connect(mapStateToProps, mapDispatchToProps)(App); 33 | 34 | -------------------------------------------------------------------------------- /redux/actions/counterActions.js: -------------------------------------------------------------------------------- 1 | //Action Types 2 | export const INCREMENT_COUNTER = "INCREMENT_COUNTER"; 3 | export const DECREMENT_COUNTER = "DECREMENT_COUNTER"; 4 | 5 | 6 | //Action Creator 7 | export const incrementCounter = () => ({ 8 | type: INCREMENT_COUNTER 9 | }); 10 | 11 | export const decrementCounter = () => ({ 12 | type: DECREMENT_COUNTER 13 | }); 14 | -------------------------------------------------------------------------------- /redux/reducers/counterReducer.js: -------------------------------------------------------------------------------- 1 | import {DECREMENT_COUNTER, INCREMENT_COUNTER} from '../actions/counterActions'; 2 | 3 | const counterReducer = (state = {value: 0}, action) => { 4 | switch (action.type) { 5 | case INCREMENT_COUNTER: 6 | return {...state, value: state.value + 1}; 7 | case DECREMENT_COUNTER: 8 | return {...state, value: state.value - 1}; 9 | default: 10 | return {...state}; 11 | } 12 | }; 13 | 14 | export default counterReducer; 15 | -------------------------------------------------------------------------------- /redux/reducers/rootReducer.js: -------------------------------------------------------------------------------- 1 | import counterReducer from './counterReducer'; 2 | import {combineReducers} from 'redux'; 3 | 4 | const rootReducer = combineReducers({ 5 | counter: counterReducer 6 | }); 7 | 8 | export default rootReducer; 9 | -------------------------------------------------------------------------------- /redux/store.js: -------------------------------------------------------------------------------- 1 | import {createStore} from 'redux'; 2 | import rootReducer from './reducers/rootReducer'; 3 | 4 | const store = createStore(rootReducer); 5 | 6 | export default store; 7 | 8 | 9 | --------------------------------------------------------------------------------