Skip to content

Commit

Permalink
Add with-redux-toolkit example (#11358)
Browse files Browse the repository at this point in the history
  • Loading branch information
jazibjafri committed Mar 26, 2020
1 parent 044ddf4 commit e02b66a
Show file tree
Hide file tree
Showing 8 changed files with 222 additions and 0 deletions.
44 changes: 44 additions & 0 deletions examples/with-redux-toolkit/README.md
@@ -0,0 +1,44 @@
# Redux Toolkit example

This example shows how to integrate Redux with Toolkit in Next.js.

Redux toolkit makes it easier to configure a redux store, create reducers or dispatch actions, along with some default middlewares. This example demonstrates each of these tasks with Next.js

## Deploy your own

Deploy the example using [ZEIT Now](https://zeit.co/now):

[![Deploy with ZEIT Now](https://zeit.co/button)](https://zeit.co/import/project?template=https://github.com/zeit/next.js/tree/canary/examples/with-redux-toolkit)

## How to use

### Using `create-next-app`

Execute [`create-next-app`](https://github.com/zeit/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example:

```bash
npx create-next-app --example with-redux-toolkit with-redux-toolkit-app
# or
yarn create next-app --example with-redux-toolkit with-redux-toolkit-app
```

### Download manually

Download the example:

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

Install it and run:

```bash
npm install
npm run dev
# or
yarn
yarn dev
```

Deploy it to the cloud with [ZEIT Now](https://zeit.co/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)).
40 changes: 40 additions & 0 deletions examples/with-redux-toolkit/components/clock.js
@@ -0,0 +1,40 @@
import React from 'react'
import { useSelector, shallowEqual } from 'react-redux'

const useClock = () => {
return useSelector(state => {
return {
lastUpdate: state.lastUpdate,
light: state.light,
}
}, shallowEqual)
}

const formatTime = time => {
// cut off except hh:mm:ss
return new Date(time).toJSON().slice(11, 19)
}

const Clock = () => {
const { lastUpdate, light } = useClock()
return (
<div className={light ? 'light' : ''}>
{formatTime(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 Clock
29 changes: 29 additions & 0 deletions examples/with-redux-toolkit/components/counter.js
@@ -0,0 +1,29 @@
import React from 'react'
import { createAction } from '@reduxjs/toolkit'
import { useSelector, useDispatch } from 'react-redux'

const useCounter = () => {
const count = useSelector(state => state.count)
const dispatch = useDispatch()
const increment = () => dispatch(createAction('INCREMENT')())
const decrement = () => dispatch(createAction('DECREMENT')())
const reset = () => dispatch(createAction('RESET')())

return { count, increment, decrement, reset }
}

const Counter = () => {
const { count, increment, decrement, reset } = useCounter()
return (
<div>
<h1>
Count: <span>{count}</span>
</h1>
<button onClick={increment}>+1</button>
<button onClick={decrement}>-1</button>
<button onClick={reset}>Reset</button>
</div>
)
}

export default Counter
19 changes: 19 additions & 0 deletions examples/with-redux-toolkit/lib/useInterval.js
@@ -0,0 +1,19 @@
import { useEffect, useRef } from 'react'

// https://overreacted.io/making-setinterval-declarative-with-react-hooks/
const useInterval = (callback, delay) => {
const savedCallback = useRef()
useEffect(() => {
savedCallback.current = callback
}, [callback])
useEffect(() => {
const handler = (...args) => savedCallback.current(...args)

if (delay !== null) {
const id = setInterval(handler, delay)
return () => clearInterval(id)
}
}, [delay])
}

export default useInterval
19 changes: 19 additions & 0 deletions examples/with-redux-toolkit/package.json
@@ -0,0 +1,19 @@
{
"name": "with-redux",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"@reduxjs/toolkit": "^1.2.5",
"next": "latest",
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-redux": "^7.1.0",
"redux": "^3.6.0",
"redux-devtools-extension": "^2.13.2"
},
"license": "ISC"
}
13 changes: 13 additions & 0 deletions examples/with-redux-toolkit/pages/_app.js
@@ -0,0 +1,13 @@
import React from 'react'
import { Provider } from 'react-redux'
import { store } from '../store'

const MyApp = ({ Component, pageProps }) => {
return (
<Provider store={store}>
<Component {...pageProps} />
</Provider>
)
}

export default MyApp
32 changes: 32 additions & 0 deletions examples/with-redux-toolkit/pages/index.js
@@ -0,0 +1,32 @@
import React from 'react'
import { createAction } from '@reduxjs/toolkit'
import { connect } from 'react-redux'
import useInterval from '../lib/useInterval'
import Clock from '../components/clock'
import Counter from '../components/counter'

const tick = createAction('TICK', light => {
return {
payload: {
light: light,
lastUpdate: Date.now(),
},
}
})

const IndexPage = ({ dispatch }) => {
// Use state or dispatch here

// Tick the time every second
useInterval(() => {
dispatch(tick(true))
}, 1000)
return (
<>
<Clock />
<Counter />
</>
)
}

export default connect(state => state)(IndexPage)
26 changes: 26 additions & 0 deletions examples/with-redux-toolkit/store.js
@@ -0,0 +1,26 @@
import { configureStore, createReducer } from '@reduxjs/toolkit'

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

const reducer = createReducer(initialState, {
TICK: (state, action) => ({
...state,
lastUpdate: action.payload.lastUpdate,
light: !!action.light,
}),
INCREMENT: (state, action) => ({ ...state, count: state.count + 1 }),
DECREMENT: (state, action) => ({ ...state, count: state.count - 1 }),
RESET: (state, action) => ({ ...state, count: initialState.count }),
})

const initializeStore = (preloadedState = initialState) => {
return configureStore({
reducer,
preloadedState,
})
}
export const store = initializeStore()

0 comments on commit e02b66a

Please sign in to comment.