Skip to content

Commit

Permalink
Merge pull request #39 from ddhp/#36-react-hook
Browse files Browse the repository at this point in the history
#36 react hook
  • Loading branch information
ddhp authored Nov 23, 2018
2 parents 99e83aa + a254328 commit 073271b
Show file tree
Hide file tree
Showing 16 changed files with 163 additions and 39 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ env:
extends:
- 'airbnb'
parser: 'babel-eslint'
plugins:
- 'react-hooks'
rules:
react/jsx-filename-extension:
- error
Expand All @@ -24,3 +26,4 @@ rules:
- 'Link'
specialLink:
- 'to'
react-hooks/rules-of-hooks: 'error'
1 change: 0 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ language: node_js

node_js:
- 8
- 6

install:
- yarn
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ This boilerplate would help you build a react/redux/react-router isomorphic/univ
- manage your style in [CSS Modules](https://github.com/css-modules/css-modules) way.
- babel v7
- optimize bundle size by implementing [tree shaking](https://webpack.js.org/guides/tree-shaking/)
- react hooks!(I hate OO components)

## Concept
### Getting Started
Expand Down
2 changes: 1 addition & 1 deletion babel.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = function babelConfig(api) {
api.cache(false);
api.cache(true); // set to other value if we handle env variable here
return {
presets: [
'@babel/react',
Expand Down
18 changes: 11 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"name": "react-isomorphic-boilerplate",
"version": "0.7.1",
"version": "0.7.2",
"main": "src/server/index.js",
"license": "MIT",
"engines": {
"node": "^6.14.0 || ^8.10.0 || >=9.10.0"
"node": "^8.10.0 || >=9.10.0"
},
"scripts": {
"start": "DEBUG=*,-nodemon*,-express*,-send,-babel*,-eslint*,-css-modules* NODE_ENV=hot npx babel-node --inspect src/server/hot/index.js",
Expand All @@ -23,6 +23,7 @@
"@babel/node": "^7.0.0",
"@babel/plugin-proposal-class-properties": "^7.1.0",
"@babel/plugin-transform-runtime": "^7.1.0",
"@babel/polyfill": "^7.0.0",
"@babel/preset-env": "^7.1.5",
"@babel/preset-react": "^7.0.0",
"@babel/register": "^7.0.0",
Expand All @@ -45,6 +46,7 @@
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jsx-a11y": "^6.1.1",
"eslint-plugin-react": "^7.11.1",
"eslint-plugin-react-hooks": "^0.0.0",
"file-loader": "^2.0.0",
"ignore-styles": "^5.0.1",
"mini-css-extract-plugin": "^0.4.4",
Expand Down Expand Up @@ -84,11 +86,11 @@
"lodash": "^4.17.4",
"normalizr": "^3.2.4",
"prop-types": "^15.6.0",
"react": "^16.4.1",
"react-dom": "^16.4.1",
"react": "^16.7.0-alpha.2",
"react-dom": "^16.7.0-alpha.2",
"react-helmet": "^5.2.0",
"react-hot-loader": "^4.3.12",
"react-redux": "^5.0.6",
"react-hot-loader": "^4.5.1",
"react-redux": "^6.0.0-beta.2",
"react-router": "^4.3.1",
"react-router-dom": "^4.3.1",
"redux": "^4.0.0",
Expand Down Expand Up @@ -124,14 +126,16 @@
],
"require": [
"@babel/register",
"@babel/polyfill",
"ignore-styles",
"css-modules-require-hook/preset",
"./src/enzymeSetup.js"
]
},
"nyc": {
"require": [
"@babel/register"
"@babel/register",
"@babel/polyfill"
],
"sourceMap": false,
"instrument": false
Expand Down
8 changes: 5 additions & 3 deletions src/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ export function accumulateCount() {
}

export function dummy() {
return {
type: 'DUMMY_ACTION',
};
return async dispatch => new Promise(() => setTimeout(() => {
dispatch({
type: 'DUMMY_ACTION',
});
}, 1000));
}

export function updateMe(me) {
Expand Down
30 changes: 30 additions & 0 deletions src/containers/Home/FormPostTotalCount.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React/* , { useEffect } */ from 'react';
import { useRedux } from '../../hooks/useRedux';
import useDummy from '../../hooks/useDummy';

import style from './style.scss'; // eslint-disable-line no-unused-vars

export default function FormPostTotalCount() {
const [state] = useRedux();
const [dummyTimes, triggerDummy] = useDummy();

return (
<div styleName="style.posts__total">
<small styleName="style.posts__small">
this component uses react hook
</small>
<div>
Total&nbsp;
{state.pages.home.posts.length}
&nbsp;Posts
</div>
<div styleName="style.posts__dummy">
{dummyTimes}
&nbsp;times dummy
</div>
<button type="button" onClick={triggerDummy}>
Dispatch Dummy
</button>
</div>
);
}
2 changes: 2 additions & 0 deletions src/containers/Home/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { connect } from 'react-redux';
import { get as _get } from 'lodash';
import { dummy as dummyAct, fetchPosts as fetchPostsAction } from '../../actions';
import FormPostComponent from './FormPost';
import FormPostTotalCount from './FormPostTotalCount';
import PostlistComponent from './Postlist';
import stdout from '../../stdout';
import style from './style.scss'; // eslint-disable-line no-unused-vars
Expand Down Expand Up @@ -45,6 +46,7 @@ export class Home extends React.Component {
</Helmet>

<FormPostComponent />
<FormPostTotalCount />

<ul styleName="style.list--posts">
{posts.map(p => <PostlistComponent post={p} key={p.id} />)}
Expand Down
4 changes: 2 additions & 2 deletions src/containers/Home/index.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ test('mapStateToProps', (t) => {
t.deepEqual(mappedProps.posts, [mockPost['1']]);
});

test('mapDispatchToProps', (t) => {
test('mapDispatchToProps', async (t) => {
const dispatchSpy = sinon.spy();
const dispatchers = mapDispatchToProps(dispatchSpy);
dispatchers.dummyAction();
await dispatchers.dummyAction();
t.true(dispatchSpy.calledOnce);
});
22 changes: 22 additions & 0 deletions src/containers/Home/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,26 @@
width: 70%;
margin: 0 auto;
}

.posts__total {
margin-left: 15%;
margin-bottom: 1rem;
border: 1px solid #eeeeee;
display: flex;
width: 70%;
padding: 1rem;
}

.posts__small {
font-size: 0.5rem;
background-color: #202860;
color: white;
padding: 0.1rem 0.2rem;
margin-right: 1rem;
}

.posts__dummy {
margin-left: 5rem;
margin-right: 1rem;
}
}
24 changes: 19 additions & 5 deletions src/entries/template.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,15 @@ import React from 'react';
import { hydrate } from 'react-dom';
import { Provider } from 'react-redux';
import { BrowserRouter as Router } from 'react-router-dom';
import { hot, setConfig } from 'react-hot-loader';
import configureStore from '../configureStore';

setConfig({
ignoreSFC: true, // RHL will be __complitely__ disabled for SFC
// pureSFC: true,
// pureRender: true, // RHL will not change render method
});

/**
* you can REUSE this template for different entries
*
Expand All @@ -25,12 +32,19 @@ export default function mount(Routes, rootReducer) {
// Create Redux store with initial state
const store = configureStore(reduxState, rootReducer);

function App() {
return (
<Provider store={store}>
<Router>
<Routes />
</Router>
</Provider>
);
}
const HotApp = hot(module)(App);

hydrate(
<Provider store={store}>
<Router>
<Routes />
</Router>
</Provider>,
<HotApp />,
document.getElementById('app-mount-point'),
);
}
10 changes: 10 additions & 0 deletions src/hooks/useDummy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { useRedux } from './useRedux';
import { dummy as dummyAction } from '../actions';

export default function useDummy() {
const [state, dispatch] = useRedux();
const triggerDummy = () => {
dispatch(dummyAction());
};
return [state.pages.home.howManyDummies, triggerDummy];
}
11 changes: 11 additions & 0 deletions src/hooks/useRedux.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// react is very likely to provide an official hook for redux
// https://reactjs.org/docs/hooks-faq.html#what-do-hooks-mean-for-popular-apis-like-redux-connect-and-react-router
import { useContext } from 'react';
import { ReactReduxContext } from 'react-redux';

export function useRedux() {
const { storeState: state, store: { dispatch } } = useContext(ReactReduxContext);
return [state, dispatch];
}

export default useRedux;
9 changes: 9 additions & 0 deletions src/reducers/pages/home.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const debug = stdout('reducer:home');
const initialState = {
count: 0,
posts: [],
howManyDummies: 0,
};

export default function homeReducer(state = initialState, action) {
Expand Down Expand Up @@ -43,6 +44,14 @@ export default function homeReducer(state = initialState, action) {
return state;
}

case 'DUMMY_ACTION': {
return update(state, {
howManyDummies: {
$set: state.howManyDummies + 1,
},
});
}

default:
return state;
}
Expand Down
2 changes: 1 addition & 1 deletion webpack.browser.babel.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default function browserConfig(env) {
const devEntry = {};
Object.keys(entry).forEach((key) => {
devEntry[key] = [];
devEntry[key].push('react-hot-loader/patch', entry[key], hotMiddlewareScript);
devEntry[key].push(entry[key], hotMiddlewareScript);
});
config.entry = devEntry;

Expand Down
Loading

0 comments on commit 073271b

Please sign in to comment.