-
Notifications
You must be signed in to change notification settings - Fork 27.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
## Changes - [x] Remove _app.js usage - [x] Migrate withRedux HOC to functional component - [x] Add correct display name - [x] Remove abstractions/boilerplate from example - [x] Add useInterval HOC from Dan
- Loading branch information
Showing
11 changed files
with
190 additions
and
189 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import React from 'react' | ||
import { Provider } from 'react-redux' | ||
import { initializeStore } from '../store' | ||
import App from 'next/app' | ||
|
||
export const withRedux = (PageComponent, { ssr = true } = {}) => { | ||
const WithRedux = ({ initialReduxState, ...props }) => { | ||
const store = getOrInitializeStore(initialReduxState) | ||
return ( | ||
<Provider store={store}> | ||
<PageComponent {...props} /> | ||
</Provider> | ||
) | ||
} | ||
|
||
// Make sure people don't use this HOC on _app.js level | ||
if (process.env.NODE_ENV !== 'production') { | ||
const isAppHoc = | ||
PageComponent === App || PageComponent.prototype instanceof App | ||
if (isAppHoc) { | ||
throw new Error('The withRedux HOC only works with PageComponents') | ||
} | ||
} | ||
|
||
// Set the correct displayName in development | ||
if (process.env.NODE_ENV !== 'production') { | ||
const displayName = | ||
PageComponent.displayName || PageComponent.name || 'Component' | ||
|
||
WithRedux.displayName = `withRedux(${displayName})` | ||
} | ||
|
||
if (ssr || PageComponent.getInitialProps) { | ||
WithRedux.getInitialProps = async context => { | ||
// Get or Create the store with `undefined` as initialState | ||
// This allows you to set a custom default initialState | ||
const reduxStore = getOrInitializeStore() | ||
|
||
// Provide the store to getInitialProps of pages | ||
context.reduxStore = reduxStore | ||
|
||
// Run getInitialProps from HOCed PageComponent | ||
const pageProps = | ||
typeof PageComponent.getInitialProps === 'function' | ||
? await PageComponent.getInitialProps(context) | ||
: {} | ||
|
||
// Pass props to PageComponent | ||
return { | ||
...pageProps, | ||
initialReduxState: reduxStore.getState() | ||
} | ||
} | ||
} | ||
|
||
return WithRedux | ||
} | ||
|
||
let reduxStore | ||
const getOrInitializeStore = initialState => { | ||
// Always make a new store if server, otherwise state is shared between requests | ||
if (typeof window === 'undefined') { | ||
return initializeStore(initialState) | ||
} | ||
|
||
// Create store if unavailable on the client and set it on the window object | ||
if (!reduxStore) { | ||
reduxStore = initializeStore(initialState) | ||
} | ||
|
||
return reduxStore | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,39 @@ | ||
import React from 'react' | ||
import { connect } from 'react-redux' | ||
import { startClock, serverRenderClock } from '../store' | ||
import Examples from '../components/examples' | ||
import { useDispatch } from 'react-redux' | ||
import { withRedux } from '../lib/redux' | ||
import useInterval from '../lib/useInterval' | ||
import Clock from '../components/clock' | ||
import Counter from '../components/counter' | ||
|
||
class Index extends React.Component { | ||
static getInitialProps ({ reduxStore, req }) { | ||
const isServer = !!req | ||
// DISPATCH ACTIONS HERE ONLY WITH `reduxStore.dispatch` | ||
reduxStore.dispatch(serverRenderClock(isServer)) | ||
|
||
return {} | ||
} | ||
|
||
componentDidMount () { | ||
// DISPATCH ACTIONS HERE FROM `mapDispatchToProps` | ||
// TO TICK THE CLOCK | ||
this.timer = setInterval(() => this.props.startClock(), 1000) | ||
} | ||
const IndexPage = () => { | ||
// Tick the time every second | ||
const dispatch = useDispatch() | ||
useInterval(() => { | ||
dispatch({ | ||
type: 'TICK', | ||
light: true, | ||
lastUpdate: Date.now() | ||
}) | ||
}, 1000) | ||
return ( | ||
<> | ||
<Clock /> | ||
<Counter /> | ||
</> | ||
) | ||
} | ||
|
||
componentWillUnmount () { | ||
clearInterval(this.timer) | ||
} | ||
IndexPage.getInitialProps = ({ reduxStore }) => { | ||
// Tick the time once, so we'll have a | ||
// valid time before first render | ||
const { dispatch } = reduxStore | ||
dispatch({ | ||
type: 'TICK', | ||
light: typeof window === 'object', | ||
lastUpdate: Date.now() | ||
}) | ||
|
||
render () { | ||
return <Examples /> | ||
} | ||
return {} | ||
} | ||
const mapDispatchToProps = { startClock } | ||
export default connect( | ||
null, | ||
mapDispatchToProps | ||
)(Index) | ||
|
||
export default withRedux(IndexPage) |
Oops, something went wrong.