Skip to content

Commit

Permalink
add example code
Browse files Browse the repository at this point in the history
  • Loading branch information
modosc committed Oct 10, 2018
1 parent 4649b79 commit f5a1561
Show file tree
Hide file tree
Showing 17 changed files with 45,270 additions and 0 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,19 @@ npm install react-responsive-redux
"redux": "^3.7.2"
```


## Usage
### Example
Inside the `example` directory run:
```
$ yarn install
$ yarn build
$ yarn start
```
Try loading the page with chrome on a desktop display and pretending to be a mobile device.
In both cases you'll notice the initial redux state is correct and there's no error in the console.

### Overview
To use `react-responsive-redux` you need to do the following:
1. Add a redux reducer to your store
2. Add mobile detection and an action dispatch in your request handler
Expand Down
9 changes: 9 additions & 0 deletions example/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"presets": [
"@babel/react",
"@babel/env"
],
"plugins": [
"react-hot-loader/babel"
]
}
17 changes: 17 additions & 0 deletions example/client/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import '@babel/polyfill'
import React from 'react'
import { hydrate } from 'react-dom'
import { Provider } from 'react-redux'
import configureStore from '../common/store/configureStore'
import App from '../common/containers/App'

const { __PRELOADED_STATE__: preloadedState } = window
const store = configureStore(preloadedState)
const rootElement = document.getElementById('app')

hydrate(
<Provider store={store}>
<App />
</Provider>,
rootElement,
)
32 changes: 32 additions & 0 deletions example/common/actions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
export const SET_COUNTER = 'SET_COUNTER'
export const INCREMENT_COUNTER = 'INCREMENT_COUNTER'
export const DECREMENT_COUNTER = 'DECREMENT_COUNTER'

export const set = value => ({
type: SET_COUNTER,
payload: value,
})

export const increment = () => ({
type: INCREMENT_COUNTER,
})

export const decrement = () => ({
type: DECREMENT_COUNTER,
})

export const incrementIfOdd = () => (dispatch, getState) => {
const { counter } = getState()

if (counter % 2 === 0) {
return
}

dispatch(increment())
}

export const incrementAsync = (delay = 1000) => (dispatch) => {
setTimeout(() => {
dispatch(increment())
}, delay)
}
14 changes: 14 additions & 0 deletions example/common/api/counter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const getRandomInt = (min, max) => (
Math.floor(Math.random() * (max - min)) + min
)

export const fetchCounter = (callback) => {
// Rather than immediately returning, we delay our code with a timeout to
// simulate asynchronous behavior
setTimeout(() => {
callback(getRandomInt(1, 100))
}, 500)

// In the case of a real world API call, you'll normally run into a Promise
// like this: API.getUser().then(user => callback(user))
}
28 changes: 28 additions & 0 deletions example/common/components/Counter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react'
import PropTypes from 'prop-types'

const Counter = ({
increment, incrementIfOdd, incrementAsync, decrement, counter,
}) => (
<p>
Clicked: {counter} times
{' '}
<button onClick={increment}>+</button>
{' '}
<button onClick={decrement}>-</button>
{' '}
<button onClick={incrementIfOdd}>Increment if odd</button>
{' '}
<button onClick={() => incrementAsync()}>Increment async</button>
</p>
)

Counter.propTypes = {
counter: PropTypes.number.isRequired,
decrement: PropTypes.func.isRequired,
increment: PropTypes.func.isRequired,
incrementAsync: PropTypes.func.isRequired,
incrementIfOdd: PropTypes.func.isRequired,
}

export default Counter
27 changes: 27 additions & 0 deletions example/common/containers/App.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react'
import { bindActionCreators } from 'redux'
import { MobileScreen, DesktopScreen } from 'react-responsive-redux'
import { connect } from 'react-redux'
import { hot } from 'react-hot-loader'
import Counter from '../components/Counter'
import * as CounterActions from '../actions'

const mapStateToProps = state => ({
counter: state.counter,
})

const mapDispatchToProps = dispatch => bindActionCreators(CounterActions, dispatch)
const App = (props = {}) =>
<div>
<div>
<MobileScreen>
<div>You are a mobile device</div>
</MobileScreen>
<DesktopScreen>
<div>You are a desktop</div>
</DesktopScreen>
</div>
<Counter {...props} />
</div>

export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(App))
16 changes: 16 additions & 0 deletions example/common/reducers/counter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { SET_COUNTER, INCREMENT_COUNTER, DECREMENT_COUNTER } from '../actions'

const counter = (state = 0, action) => {
switch (action.type) {
case SET_COUNTER:
return action.payload
case INCREMENT_COUNTER:
return state + 1
case DECREMENT_COUNTER:
return state - 1
default:
return state
}
}

export default counter
11 changes: 11 additions & 0 deletions example/common/reducers/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { combineReducers } from 'redux'
import { reducer as responsiveReducer } from 'react-responsive-redux'

import counter from './counter'

const rootReducer = combineReducers({
counter,
responsive: responsiveReducer,
})

export default rootReducer
26 changes: 26 additions & 0 deletions example/common/store/configureStore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { createStore, applyMiddleware, compose} from 'redux'
import thunk from 'redux-thunk'
import rootReducer from '../reducers'

const composeEnhancers = typeof window !== 'undefined' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose

const configureStore = (preloadedState) => {
const store = createStore(
rootReducer,
preloadedState,
composeEnhancers(
applyMiddleware(thunk)
)
)

if (module.hot) {
// Enable Webpack hot module replacement for reducers
module.hot.accept('../reducers', () => {
store.replaceReducer(rootReducer)
})
}

return store
}

export default configureStore

0 comments on commit f5a1561

Please sign in to comment.