Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions examples/with-redux-reselect-recompose/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"presets": [
"next/babel"
],
"plugins": [
["module-resolver", {
"root": ["./"]
}]
]
}
46 changes: 46 additions & 0 deletions examples/with-redux-reselect-recompose/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"parser": "babel-eslint",
"plugins": [
"react"
],
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module",
"ecmaFeatures": {
"jsx": true
}
},
"env": {
"browser": true,
"amd": true,
"es6": true,
"node": true,
"mocha": true
},
"extends": [
"airbnb",
"eslint:recommended",
"plugin:import/errors",
"plugin:import/warnings"
],
"rules": {
"quotes": [ 1, "single" ],
"no-undef": 1,
"no-extra-semi": 1,
"no-console": 1,
"no-unused-vars": 1,
"no-trailing-spaces": [1, { "skipBlankLines": true }],
"no-unreachable": 1,
"react/jsx-uses-react": 1,
"react/jsx-uses-vars": 1,
"react/jsx-filename-extension": 0,
"react/prop-types": 0, // Disabled by this issue https://github.com/acdlite/recompose/issues/150
"import/no-unresolved": [0, {"commonjs": true, "amd": true}],
"import/named": 1,
"import/namespace": 1,
"import/default": 1,
"import/export": 1,
"import/no-extraneous-dependencies": 0,
"import/extensions": 0
}
}
1 change: 1 addition & 0 deletions examples/with-redux-reselect-recompose/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
36 changes: 36 additions & 0 deletions examples/with-redux-reselect-recompose/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[![Deploy to now](https://deploy.now.sh/static/button.svg)](https://deploy.now.sh/?repo=https://github.com/zeit/next.js/tree/master/examples/with-redux)

# Redux with reselect and recompose example

## How to use

Download the example [or clone the repo](https://github.com/zeit/next.js):

```bash
curl https://codeload.github.com/zeit/next.js/tar.gz/master | tar -xz --strip=2 next.js-master/examples/with-redux-reselect-recompose
cd with-redux-reselect-recompose
```

Install it and run:

```bash
npm install
npm run dev
```

OR

```bash
yarn
yarn dev
```


Deploy it to the cloud with [now](https://zeit.co/now) ([download](https://zeit.co/download))

```bash
now
```

## The idea behind the example
This example is based on the great work of [with-redux](https://github.com/zeit/next.js/tree/v3-beta/examples/with-redux) example with the addition of [reselect](https://github.com/reactjs/reselect) and [recompose](https://github.com/acdlite/recompose)
9 changes: 9 additions & 0 deletions examples/with-redux-reselect-recompose/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { TICK, ADD } from 'constants/actionTypes'

export const addCount = () => ({ type: ADD })

export const setClock = (light, ts) => ({ type: TICK, light, ts })

export const serverRenderClock = isServer => dispatch => dispatch(setClock(!isServer, Date.now()))

export const startClock = () => dispatch => setInterval(() => dispatch(setClock(true, Date.now())), 800)
23 changes: 23 additions & 0 deletions examples/with-redux-reselect-recompose/components/addCount.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react'
import PropTypes from 'prop-types'
import { compose, setDisplayName, pure, setPropTypes } from 'recompose'

const AddCount = ({ count, addCount }) =>
<div>
<style jsx>{`
div {
padding: 0 0 20px 0;
}
`}</style>
<h1>AddCount: <span>{count}</span></h1>
<button onClick={addCount}>Add To Count</button>
</div>

export default compose(
setDisplayName('AddCount'),
setPropTypes({
count: PropTypes.number,
addCount: PropTypes.func
}),
pure
)(AddCount)
34 changes: 34 additions & 0 deletions examples/with-redux-reselect-recompose/components/clock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react'
import PropTypes from 'prop-types'
import { compose, pure, setDisplayName, setPropTypes } from 'recompose'

const format = t => `${pad(t.getUTCHours())}:${pad(t.getUTCMinutes())}:${pad(t.getUTCSeconds())}`

const pad = n => n < 10 ? `0${n}` : n

const Clock = ({ lastUpdate, light }) =>
<div className={light ? 'light' : ''}>
{format(new Date(lastUpdate))}
<style jsx>{`
div {
padding: 15px;
display: inline-block;
color: #82FA58;
font: 50px menlo, monaco, monospace;
background-color: #000;
}

.light {
background-color: #999;
}
`}</style>
</div>

export default compose(
setDisplayName('Clock'),
setPropTypes({
lastUpdate: PropTypes.number,
light: PropTypes.bool
}),
pure
)(Clock)
29 changes: 29 additions & 0 deletions examples/with-redux-reselect-recompose/components/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React from 'react'
import PropTypes from 'prop-types'
import Link from 'next/link'
import { compose, setDisplayName, pure, setPropTypes } from 'recompose'
import Clock from './clock'
import AddCount from './addCount'

const Page = ({ title, linkTo, light, lastUpdate, count, addCount }) =>
<div>
<h1>{title}</h1>
<Clock lastUpdate={lastUpdate} light={light} />
<AddCount count={count} addCount={addCount} />
<nav>
<Link href={linkTo}><a>Navigate</a></Link>
</nav>
</div>

export default compose(
setDisplayName('Page'),
setPropTypes({
title: PropTypes.string,
linkTo: PropTypes.string,
light: PropTypes.bool,
lastUpdate: PropTypes.number,
count: PropTypes.number,
addCount: PropTypes.func
}),
pure
)(Page)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const ADD = 'ADD'
export const TICK = 'TICK'
17 changes: 17 additions & 0 deletions examples/with-redux-reselect-recompose/containers/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { connect } from 'react-redux'
import { addCount } from 'actions'
import { selectLight, selectLastUpdate, selectCount } from 'selectors'
import { createSelector } from 'reselect'
import { compose, setDisplayName, pure } from 'recompose'
import Page from 'components/page'

export default compose(
setDisplayName('PageContainer'),
connect(createSelector(
selectLight(),
selectLastUpdate(),
selectCount(),
(light, lastUpdate, count) => ({ light, lastUpdate, count })
), { addCount }),
pure
)(Page)
35 changes: 35 additions & 0 deletions examples/with-redux-reselect-recompose/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{
"name": "with-redux-reselect-recompose",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start",
"lint": "eslint --ext .js,.js ."
},
"dependencies": {
"babel-plugin-module-resolver": "^2.7.1",
"next": "latest",
"next-redux-wrapper": "^1.0.0",
"prop-types": "^15.5.10",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-redux": "^5.0.1",
"recompose": "^0.23.5",
"redux": "^3.6.0",
"redux-logger": "^3.0.6",
"redux-thunk": "^2.2.0",
"reselect": "^3.0.1"
},
"author": "Phuc Nguyen Hoang",
"license": "MIT",
"devDependencies": {
"babel-eslint": "7.1.1",
"eslint": "3.11.1",
"eslint-config-airbnb": "13.0.0",
"eslint-loader": "^1.9.0",
"eslint-plugin-import": "2.2.0",
"eslint-plugin-jsx-a11y": "2.2.3",
"eslint-plugin-react": "6.7.1"
}
}
30 changes: 30 additions & 0 deletions examples/with-redux-reselect-recompose/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { startClock, addCount, serverRenderClock } from 'actions'
import Page from 'containers/page'
import withRedux from 'next-redux-wrapper'
import { compose, setDisplayName, pure, lifecycle, withProps } from 'recompose'
import initStore from '../store'

const Counter = compose(
setDisplayName('IndexPage'),
withProps({
title: 'Index page',
linkTo: '/other'
}),
lifecycle({
componentDidMount () {
this.timer = this.props.startClock()
},
componentWillUnmount () {
clearInterval(this.timer)
}
}),
pure
)(Page)

Counter.getInitialProps = ({ store, isServer }) => {
store.dispatch(serverRenderClock(isServer))
store.dispatch(addCount())
return { isServer }
}

export default withRedux(initStore, null, { startClock })(Counter)
30 changes: 30 additions & 0 deletions examples/with-redux-reselect-recompose/pages/other.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { startClock, addCount, serverRenderClock } from 'actions'
import Page from 'containers/page'
import withRedux from 'next-redux-wrapper'
import { compose, setDisplayName, pure, lifecycle, withProps } from 'recompose'
import initStore from '../store'

const Counter = compose(
setDisplayName('OtherPage'),
withProps({
title: 'Other page',
linkTo: '/'
}),
lifecycle({
componentDidMount () {
this.timer = this.props.startClock()
},
componentWillUnmount () {
clearInterval(this.timer)
}
}),
pure
)(Page)

Counter.getInitialProps = ({ store, isServer }) => {
store.dispatch(serverRenderClock(isServer))
store.dispatch(addCount())
return { isServer }
}

export default withRedux(initStore, null, { startClock })(Counter)
30 changes: 30 additions & 0 deletions examples/with-redux-reselect-recompose/reducers/count.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { ADD, TICK } from 'constants/actionTypes'

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

export default (state = initialState, action) => {
const { type, ts, light } = action

switch (type) {
case TICK: {
return Object.assign({}, state, {
lastUpdate: ts,
light: !!light
})
}

case ADD: {
return Object.assign({}, state, {
count: state.count + 1
})
}

default: {
return state
}
}
}
10 changes: 10 additions & 0 deletions examples/with-redux-reselect-recompose/reducers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { combineReducers } from 'redux'
import count, { initialState as countState } from './count'

export const intitialState = {
count: countState
}

export default combineReducers({
count
})
18 changes: 18 additions & 0 deletions examples/with-redux-reselect-recompose/selectors/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { createSelector } from 'reselect'

export const selectState = () => state => state.count

export const selectCount = () => createSelector(
selectState(),
count => count.count
)

export const selectLight = () => createSelector(
selectState(),
count => count.light
)

export const selectLastUpdate = () => createSelector(
selectState(),
count => count.lastUpdate
)
13 changes: 13 additions & 0 deletions examples/with-redux-reselect-recompose/store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import thunkMiddleware from 'redux-thunk'
import { createStore, applyMiddleware, compose } from 'redux'
import { createLogger } from 'redux-logger'
import reducer, { initialState } from 'reducers'

export default (state = initialState) => {
const middlewares = [thunkMiddleware, createLogger()]
return createStore(
reducer,
state,
compose(applyMiddleware(...middlewares))
)
}