From e02b66a52c0a9bb837845e6ec4e6356b3ee1697f Mon Sep 17 00:00:00 2001 From: Jazib Jafri <42325130+JazibJafri@users.noreply.github.com> Date: Thu, 26 Mar 2020 23:15:40 +0500 Subject: [PATCH] Add with-redux-toolkit example (#11358) --- examples/with-redux-toolkit/README.md | 44 +++++++++++++++++++ .../with-redux-toolkit/components/clock.js | 40 +++++++++++++++++ .../with-redux-toolkit/components/counter.js | 29 ++++++++++++ .../with-redux-toolkit/lib/useInterval.js | 19 ++++++++ examples/with-redux-toolkit/package.json | 19 ++++++++ examples/with-redux-toolkit/pages/_app.js | 13 ++++++ examples/with-redux-toolkit/pages/index.js | 32 ++++++++++++++ examples/with-redux-toolkit/store.js | 26 +++++++++++ 8 files changed, 222 insertions(+) create mode 100644 examples/with-redux-toolkit/README.md create mode 100644 examples/with-redux-toolkit/components/clock.js create mode 100644 examples/with-redux-toolkit/components/counter.js create mode 100644 examples/with-redux-toolkit/lib/useInterval.js create mode 100644 examples/with-redux-toolkit/package.json create mode 100644 examples/with-redux-toolkit/pages/_app.js create mode 100644 examples/with-redux-toolkit/pages/index.js create mode 100644 examples/with-redux-toolkit/store.js diff --git a/examples/with-redux-toolkit/README.md b/examples/with-redux-toolkit/README.md new file mode 100644 index 0000000000000..3c3cbae41e058 --- /dev/null +++ b/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)). diff --git a/examples/with-redux-toolkit/components/clock.js b/examples/with-redux-toolkit/components/clock.js new file mode 100644 index 0000000000000..d394d9376cf26 --- /dev/null +++ b/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 ( +
+ {formatTime(lastUpdate)} + +
+ ) +} + +export default Clock diff --git a/examples/with-redux-toolkit/components/counter.js b/examples/with-redux-toolkit/components/counter.js new file mode 100644 index 0000000000000..05ab067e968e0 --- /dev/null +++ b/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 ( +
+

+ Count: {count} +

+ + + +
+ ) +} + +export default Counter diff --git a/examples/with-redux-toolkit/lib/useInterval.js b/examples/with-redux-toolkit/lib/useInterval.js new file mode 100644 index 0000000000000..066d08ee254b5 --- /dev/null +++ b/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 diff --git a/examples/with-redux-toolkit/package.json b/examples/with-redux-toolkit/package.json new file mode 100644 index 0000000000000..91f06b4bddce9 --- /dev/null +++ b/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" +} diff --git a/examples/with-redux-toolkit/pages/_app.js b/examples/with-redux-toolkit/pages/_app.js new file mode 100644 index 0000000000000..025a8be8c9b98 --- /dev/null +++ b/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 ( + + + + ) +} + +export default MyApp diff --git a/examples/with-redux-toolkit/pages/index.js b/examples/with-redux-toolkit/pages/index.js new file mode 100644 index 0000000000000..30da73b0c7efa --- /dev/null +++ b/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 ( + <> + + + + ) +} + +export default connect(state => state)(IndexPage) diff --git a/examples/with-redux-toolkit/store.js b/examples/with-redux-toolkit/store.js new file mode 100644 index 0000000000000..9c2a9d3c05e76 --- /dev/null +++ b/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()