├── chapter-03
├── flux
│ ├── config
│ │ ├── jest
│ │ │ ├── CSSStub.js
│ │ │ └── FileStub.js
│ │ ├── polyfills.js
│ │ └── env.js
│ ├── src
│ │ ├── index.css
│ │ ├── AppDispatcher.js
│ │ ├── ActionTypes.js
│ │ ├── index.js
│ │ ├── Actions.js
│ │ ├── views
│ │ │ ├── ControlPanel.js
│ │ │ └── Summary.js
│ │ └── stores
│ │ │ └── CounterStore.js
│ ├── public
│ │ └── favicon.ico
│ ├── .gitignore
│ └── scripts
│ │ └── test.js
├── react-redux
│ ├── config
│ │ ├── jest
│ │ │ ├── CSSStub.js
│ │ │ └── FileStub.js
│ │ └── polyfills.js
│ ├── src
│ │ ├── index.css
│ │ ├── ActionTypes.js
│ │ ├── Store.js
│ │ ├── Actions.js
│ │ ├── index.js
│ │ ├── Reducer.js
│ │ └── views
│ │ │ ├── ControlPanel.js
│ │ │ └── Summary.js
│ ├── public
│ │ └── favicon.ico
│ └── scripts
│ │ └── test.js
├── redux_basic
│ ├── config
│ │ ├── jest
│ │ │ ├── CSSStub.js
│ │ │ └── FileStub.js
│ │ └── polyfills.js
│ ├── src
│ │ ├── index.css
│ │ ├── ActionTypes.js
│ │ ├── index.js
│ │ ├── Store.js
│ │ ├── Actions.js
│ │ ├── Reducer.js
│ │ └── views
│ │ │ ├── ControlPanel.js
│ │ │ └── Summary.js
│ ├── public
│ │ └── favicon.ico
│ └── scripts
│ │ └── test.js
├── redux_smart_dumb
│ ├── config
│ │ ├── jest
│ │ │ ├── CSSStub.js
│ │ │ └── FileStub.js
│ │ └── polyfills.js
│ ├── src
│ │ ├── index.css
│ │ ├── ActionTypes.js
│ │ ├── index.js
│ │ ├── Store.js
│ │ ├── Actions.js
│ │ ├── Reducer.js
│ │ └── views
│ │ │ └── ControlPanel.js
│ ├── public
│ │ └── favicon.ico
│ └── scripts
│ │ └── test.js
└── redux_with_context
│ ├── config
│ ├── jest
│ │ ├── CSSStub.js
│ │ └── FileStub.js
│ └── polyfills.js
│ ├── src
│ ├── index.css
│ ├── ActionTypes.js
│ ├── Store.js
│ ├── index.js
│ ├── Actions.js
│ ├── Reducer.js
│ ├── Provider.js
│ └── views
│ │ └── ControlPanel.js
│ ├── public
│ └── favicon.ico
│ └── scripts
│ └── test.js
├── chapter-02
├── controlpanel
│ ├── config
│ │ ├── jest
│ │ │ ├── CSSStub.js
│ │ │ └── FileStub.js
│ │ └── polyfills.js
│ ├── src
│ │ ├── index.css
│ │ ├── index.js
│ │ └── ControlPanel.js
│ ├── public
│ │ └── favicon.ico
│ ├── .gitignore
│ └── scripts
│ │ └── test.js
└── controlpanel_with_summary
│ ├── config
│ ├── jest
│ │ ├── CSSStub.js
│ │ └── FileStub.js
│ └── polyfills.js
│ ├── src
│ ├── index.css
│ ├── index.js
│ └── ControlPanel.js
│ ├── public
│ └── favicon.ico
│ ├── .gitignore
│ └── scripts
│ └── test.js
├── chapter-01
├── first_react_app
│ ├── config
│ │ ├── jest
│ │ │ ├── CSSStub.js
│ │ │ └── FileStub.js
│ │ └── polyfills.js
│ ├── src
│ │ ├── index.css
│ │ ├── App.test.js
│ │ ├── index.js
│ │ ├── App.css
│ │ ├── App.js
│ │ └── ClickCounter.js
│ ├── public
│ │ └── favicon.ico
│ ├── .gitignore
│ └── scripts
│ │ └── test.js
└── jquery_solution
│ ├── clickCounter.js
│ └── index.html
├── chapter-04
├── todo
│ ├── src
│ │ ├── filter
│ │ │ ├── actionTypes.js
│ │ │ ├── actions.js
│ │ │ ├── index.js
│ │ │ ├── reducer.js
│ │ │ └── views
│ │ │ │ ├── filters.js
│ │ │ │ ├── style.css
│ │ │ │ └── link.js
│ │ ├── constants.js
│ │ ├── todos
│ │ │ ├── actionTypes.js
│ │ │ ├── index.js
│ │ │ ├── views
│ │ │ │ ├── todos.js
│ │ │ │ └── todoItem.js
│ │ │ ├── actions.js
│ │ │ └── reducer.js
│ │ ├── TodoApp.js
│ │ ├── index.js
│ │ └── Store.js
│ ├── public
│ │ └── favicon.ico
│ ├── .gitignore
│ └── package.json
└── todo_controlled_component
│ ├── src
│ ├── filter
│ │ ├── actionTypes.js
│ │ ├── actions.js
│ │ ├── index.js
│ │ ├── reducer.js
│ │ └── views
│ │ │ ├── filters.js
│ │ │ ├── style.css
│ │ │ └── link.js
│ ├── constants.js
│ ├── todos
│ │ ├── actionTypes.js
│ │ ├── index.js
│ │ ├── views
│ │ │ ├── todos.js
│ │ │ └── todoItem.js
│ │ ├── actions.js
│ │ └── reducer.js
│ ├── TodoApp.js
│ ├── index.js
│ └── Store.js
│ ├── public
│ └── favicon.ico
│ └── package.json
├── chapter-05
├── todo_perf
│ ├── src
│ │ ├── filter
│ │ │ ├── actionTypes.js
│ │ │ ├── actions.js
│ │ │ ├── index.js
│ │ │ ├── reducer.js
│ │ │ └── views
│ │ │ │ ├── filters.js
│ │ │ │ ├── style.css
│ │ │ │ └── link.js
│ │ ├── constants.js
│ │ ├── todos
│ │ │ ├── actionTypes.js
│ │ │ ├── index.js
│ │ │ ├── views
│ │ │ │ └── todos.js
│ │ │ ├── actions.js
│ │ │ └── reducer.js
│ │ ├── TodoApp.js
│ │ ├── index.js
│ │ └── Store.js
│ ├── public
│ │ └── favicon.ico
│ └── package.json
├── todo_with_selector
│ ├── src
│ │ ├── filter
│ │ │ ├── actionTypes.js
│ │ │ ├── actions.js
│ │ │ ├── index.js
│ │ │ ├── reducer.js
│ │ │ └── views
│ │ │ │ ├── filters.js
│ │ │ │ ├── style.css
│ │ │ │ └── link.js
│ │ ├── constants.js
│ │ ├── todos
│ │ │ ├── actionTypes.js
│ │ │ ├── index.js
│ │ │ ├── views
│ │ │ │ ├── todos.js
│ │ │ │ └── todoList.js
│ │ │ ├── actions.js
│ │ │ ├── selector.js
│ │ │ └── reducer.js
│ │ ├── TodoApp.js
│ │ ├── index.js
│ │ └── Store.js
│ ├── public
│ │ └── favicon.ico
│ ├── package.json
│ └── test
│ │ ├── filter
│ │ └── views
│ │ │ └── filters.test.js
│ │ └── todos
│ │ ├── actions.test.js
│ │ └── views
│ │ └── todoList.test.js
└── .gitignore
├── chapter-10
├── todo_animated
│ ├── src
│ │ ├── filter
│ │ │ ├── actionTypes.js
│ │ │ ├── actions.js
│ │ │ ├── index.js
│ │ │ ├── reducer.js
│ │ │ └── views
│ │ │ │ ├── filters.js
│ │ │ │ ├── style.css
│ │ │ │ └── link.js
│ │ ├── constants.js
│ │ ├── todos
│ │ │ ├── actionTypes.js
│ │ │ ├── index.js
│ │ │ ├── views
│ │ │ │ ├── todos.js
│ │ │ │ ├── todoItem.css
│ │ │ │ └── todoList.js
│ │ │ ├── actions.js
│ │ │ ├── selector.js
│ │ │ └── reducer.js
│ │ ├── TodoApp.js
│ │ ├── index.js
│ │ └── Store.js
│ ├── public
│ │ └── favicon.ico
│ └── package.json
├── todo_react_motion
│ ├── src
│ │ ├── filter
│ │ │ ├── actionTypes.js
│ │ │ ├── actions.js
│ │ │ ├── index.js
│ │ │ ├── reducer.js
│ │ │ └── views
│ │ │ │ ├── filters.js
│ │ │ │ ├── style.css
│ │ │ │ └── link.js
│ │ ├── constants.js
│ │ ├── todos
│ │ │ ├── actionTypes.js
│ │ │ ├── index.js
│ │ │ ├── views
│ │ │ │ └── todos.js
│ │ │ ├── actions.js
│ │ │ ├── selector.js
│ │ │ └── reducer.js
│ │ ├── TodoApp.js
│ │ ├── index.js
│ │ └── Store.js
│ ├── public
│ │ └── favicon.ico
│ └── package.json
└── animation_types
│ ├── css3_sample.html
│ ├── setInterval_animation.html
│ └── simulate_requestAnimationFrame.html
├── chapter-07
├── weather_redux
│ ├── src
│ │ ├── city_selector
│ │ │ └── index.js
│ │ ├── weather
│ │ │ ├── status.js
│ │ │ ├── index.js
│ │ │ ├── actionTypes.js
│ │ │ ├── reducer.js
│ │ │ └── actions.js
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── App.js
│ │ └── Store.js
│ ├── public
│ │ └── favicon.ico
│ ├── .gitignore
│ ├── test
│ │ └── weather
│ │ │ └── reducer.test.js
│ └── package.json
├── weather_redux_improved
│ ├── src
│ │ ├── city_selector
│ │ │ └── index.js
│ │ ├── weather
│ │ │ ├── status.js
│ │ │ ├── index.js
│ │ │ ├── actionTypes.js
│ │ │ └── reducer.js
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── App.js
│ │ └── Store.js
│ ├── public
│ │ └── favicon.ico
│ ├── .gitignore
│ └── package.json
└── weather_react
│ ├── src
│ ├── index.css
│ └── index.js
│ ├── public
│ └── favicon.ico
│ ├── .gitignore
│ └── package.json
├── chapter-09
├── weather_with_promise_middleware
│ ├── src
│ │ ├── city_selector
│ │ │ └── index.js
│ │ ├── weather
│ │ │ ├── status.js
│ │ │ ├── index.js
│ │ │ ├── actionTypes.js
│ │ │ ├── actions.js
│ │ │ └── reducer.js
│ │ ├── index.css
│ │ ├── index.js
│ │ ├── App.js
│ │ ├── middleware
│ │ │ └── promise_middleware.js
│ │ └── Store.js
│ ├── public
│ │ └── favicon.ico
│ └── package.json
├── reset_enhancer
│ ├── package.json
│ ├── src
│ │ └── reset.js
│ └── test
│ │ └── reset.test.js
└── promise_middleware
│ ├── package.json
│ └── src
│ ├── simple.js
│ └── advanced.js
├── chapter-12
├── isomorphic
│ ├── public
│ │ └── favicon.ico
│ ├── src
│ │ ├── index.js
│ │ ├── components
│ │ │ ├── Counter
│ │ │ │ ├── actionTypes.js
│ │ │ │ ├── index.js
│ │ │ │ ├── actions.js
│ │ │ │ ├── reducer.js
│ │ │ │ └── view.js
│ │ │ └── TopMenu
│ │ │ │ └── index.js
│ │ ├── pages
│ │ │ ├── About.js
│ │ │ ├── NotFound.js
│ │ │ ├── App.js
│ │ │ ├── Home.js
│ │ │ └── CounterPage.js
│ │ ├── enhancer
│ │ │ └── reset.js
│ │ └── Store.js
│ ├── config
│ │ ├── jest
│ │ │ ├── fileTransform.js
│ │ │ └── cssTransform.js
│ │ └── polyfills.js
│ ├── server
│ │ ├── index.js
│ │ ├── views
│ │ │ └── index.ejs
│ │ └── app.prod.js
│ └── scripts
│ │ └── test.js
└── express_server
│ ├── public
│ └── favicon.ico
│ ├── src
│ ├── components
│ │ ├── Counter
│ │ │ ├── actionTypes.js
│ │ │ ├── index.js
│ │ │ ├── actions.js
│ │ │ ├── reducer.js
│ │ │ └── view.js
│ │ └── TopMenu
│ │ │ └── index.js
│ ├── pages
│ │ ├── About.js
│ │ ├── NotFound.js
│ │ ├── App.js
│ │ ├── Home.js
│ │ └── CounterPage.js
│ ├── index.js
│ ├── enhancer
│ │ └── reset.js
│ └── Store.js
│ ├── config
│ ├── jest
│ │ ├── fileTransform.js
│ │ └── cssTransform.js
│ └── polyfills.js
│ ├── server
│ ├── index.js
│ ├── views
│ │ └── index.ejs
│ └── app.prod.js
│ └── scripts
│ └── test.js
├── chapter-11
├── chunked_with_redux
│ ├── public
│ │ └── favicon.ico
│ ├── src
│ │ ├── components
│ │ │ ├── Counter
│ │ │ │ ├── actionTypes.js
│ │ │ │ ├── index.js
│ │ │ │ ├── actions.js
│ │ │ │ ├── reducer.js
│ │ │ │ └── view.js
│ │ │ └── TopMenu
│ │ │ │ └── index.js
│ │ ├── pages
│ │ │ ├── About.js
│ │ │ ├── NotFound.js
│ │ │ ├── App.js
│ │ │ ├── CounterPage.js
│ │ │ └── Home.js
│ │ ├── index.js
│ │ ├── enhancer
│ │ │ └── reset.js
│ │ └── Store.js
│ ├── config
│ │ ├── jest
│ │ │ ├── fileTransform.js
│ │ │ └── cssTransform.js
│ │ └── polyfills.js
│ └── scripts
│ │ └── test.js
├── react_router_basic
│ ├── public
│ │ └── favicon.ico
│ ├── src
│ │ ├── pages
│ │ │ ├── About.js
│ │ │ ├── NotFound.js
│ │ │ ├── App.js
│ │ │ └── Home.js
│ │ ├── index.js
│ │ ├── components
│ │ │ └── TopMenu
│ │ │ │ └── index.js
│ │ ├── Store.js
│ │ └── Routes.js
│ ├── .gitignore
│ └── package.json
└── react_router_chunked
│ ├── public
│ └── favicon.ico
│ ├── src
│ ├── pages
│ │ ├── About.js
│ │ ├── NotFound.js
│ │ ├── App.js
│ │ └── Home.js
│ ├── index.js
│ ├── components
│ │ └── TopMenu
│ │ │ └── index.js
│ └── Store.js
│ ├── config
│ ├── jest
│ │ ├── fileTransform.js
│ │ └── cssTransform.js
│ └── polyfills.js
│ └── scripts
│ └── test.js
├── chapter-06
├── hoc
│ ├── src
│ │ ├── proxy
│ │ │ ├── removeUserPropHOC.js
│ │ │ ├── AddNewPropsHOC.js
│ │ │ ├── StyleHOC.js
│ │ │ └── RefsHOC.js
│ │ └── inheritance
│ │ │ ├── cacheHOC.js
│ │ │ ├── OnlyForLoggedinHOC.js
│ │ │ ├── ModifyPropsHOC.js
│ │ │ └── removeUserPropHOC.js
│ ├── package.json
│ └── test
│ │ ├── proxy
│ │ ├── RefsHOC.test.js
│ │ ├── removeUserPropHOC.test.js
│ │ ├── StyleHOC.test.js
│ │ ├── AddNewPropsHOC.test.js
│ │ └── ConnectHOC.test.js
│ │ └── inheritance
│ │ ├── removeUserPropHOC.test.js
│ │ ├── OnlyForLoggedInHOC.test.js
│ │ └── ModifyPropsHOC.test.js
└── function_as_child
│ ├── src
│ ├── AddUserProp.js
│ └── CountDown.js
│ ├── test
│ ├── AddUserProp.test.js
│ └── countDown.test.js
│ └── package.json
├── README.md
└── .gitignore
/chapter-03/flux/config/jest/CSSStub.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel/config/jest/CSSStub.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/chapter-03/react-redux/config/jest/CSSStub.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/chapter-03/redux_basic/config/jest/CSSStub.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/chapter-01/first_react_app/config/jest/CSSStub.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/chapter-03/flux/config/jest/FileStub.js:
--------------------------------------------------------------------------------
1 | module.exports = "test-file-stub";
2 |
--------------------------------------------------------------------------------
/chapter-03/redux_smart_dumb/config/jest/CSSStub.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/config/jest/CSSStub.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel/config/jest/FileStub.js:
--------------------------------------------------------------------------------
1 | module.exports = "test-file-stub";
2 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel_with_summary/config/jest/CSSStub.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/chapter-03/react-redux/config/jest/FileStub.js:
--------------------------------------------------------------------------------
1 | module.exports = "test-file-stub";
2 |
--------------------------------------------------------------------------------
/chapter-03/redux_basic/config/jest/FileStub.js:
--------------------------------------------------------------------------------
1 | module.exports = "test-file-stub";
2 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/filter/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const SET_FILTER = 'FILTER/SET';
2 |
--------------------------------------------------------------------------------
/chapter-01/first_react_app/config/jest/FileStub.js:
--------------------------------------------------------------------------------
1 | module.exports = "test-file-stub";
2 |
--------------------------------------------------------------------------------
/chapter-03/redux_smart_dumb/config/jest/FileStub.js:
--------------------------------------------------------------------------------
1 | module.exports = "test-file-stub";
2 |
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/config/jest/FileStub.js:
--------------------------------------------------------------------------------
1 | module.exports = "test-file-stub";
2 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/filter/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const SET_FILTER = 'FILTER/SET';
2 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/filter/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const SET_FILTER = 'FILTER/SET';
2 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/filter/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const SET_FILTER = 'FILTER/SET';
2 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel_with_summary/config/jest/FileStub.js:
--------------------------------------------------------------------------------
1 | module.exports = "test-file-stub";
2 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/filter/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const SET_FILTER = 'FILTER/SET';
2 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/filter/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const SET_FILTER = 'FILTER/SET';
2 |
--------------------------------------------------------------------------------
/chapter-03/flux/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux/src/city_selector/index.js:
--------------------------------------------------------------------------------
1 | import view from './view.js';
2 |
3 | export {view};
4 |
--------------------------------------------------------------------------------
/chapter-03/flux/src/AppDispatcher.js:
--------------------------------------------------------------------------------
1 | import {Dispatcher} from 'flux';
2 |
3 | export default new Dispatcher();
4 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux_improved/src/city_selector/index.js:
--------------------------------------------------------------------------------
1 | import view from './view.js';
2 |
3 | export {view};
4 |
--------------------------------------------------------------------------------
/chapter-01/first_react_app/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-03/react-redux/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-03/redux_basic/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-07/weather_react/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-03/flux/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-03/flux/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-03/flux/src/ActionTypes.js:
--------------------------------------------------------------------------------
1 | export const INCREMENT = 'increment';
2 |
3 | export const DECREMENT = 'decrement';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-03/redux_smart_dumb/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-04/todo/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-04/todo/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/src/city_selector/index.js:
--------------------------------------------------------------------------------
1 | import view from './view.js';
2 |
3 | export {view};
4 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel_with_summary/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/chapter-03/react-redux/src/ActionTypes.js:
--------------------------------------------------------------------------------
1 | export const INCREMENT = 'increment';
2 |
3 | export const DECREMENT = 'decrement';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-03/redux_basic/src/ActionTypes.js:
--------------------------------------------------------------------------------
1 | export const INCREMENT = 'increment';
2 |
3 | export const DECREMENT = 'decrement';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-05/todo_perf/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-02/controlpanel/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-02/controlpanel/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-03/react-redux/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-03/react-redux/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-03/redux_basic/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-03/redux_basic/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-03/redux_smart_dumb/src/ActionTypes.js:
--------------------------------------------------------------------------------
1 | export const INCREMENT = 'increment';
2 |
3 | export const DECREMENT = 'decrement';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/src/ActionTypes.js:
--------------------------------------------------------------------------------
1 | export const INCREMENT = 'increment';
2 |
3 | export const DECREMENT = 'decrement';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/constants.js:
--------------------------------------------------------------------------------
1 | export const FilterTypes = {
2 | ALL: '全部',
3 | COMPLETED: '已完成',
4 | UNCOMPLETED: '未完成'
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-12/isomorphic/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/index.js:
--------------------------------------------------------------------------------
1 | import {renderRoutes} from './Routes.js';
2 |
3 | renderRoutes(document.getElementById('root'));
4 |
5 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/constants.js:
--------------------------------------------------------------------------------
1 | export const FilterTypes = {
2 | ALL: '全部',
3 | COMPLETED: '已完成',
4 | UNCOMPLETED: '未完成'
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/chapter-07/weather_react/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-07/weather_react/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-07/weather_redux/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-07/weather_redux/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-10/todo_animated/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-10/todo_animated/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-12/express_server/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-12/express_server/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-01/first_react_app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-01/first_react_app/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-03/redux_smart_dumb/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-03/redux_smart_dumb/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/constants.js:
--------------------------------------------------------------------------------
1 | export const FilterTypes = {
2 | ALL: '全部',
3 | COMPLETED: '已完成',
4 | UNCOMPLETED: '未完成'
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-10/todo_react_motion/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-03/redux_with_context/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-05/todo_with_selector/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/constants.js:
--------------------------------------------------------------------------------
1 | export const FilterTypes = {
2 | ALL: '全部',
3 | COMPLETED: '已完成',
4 | UNCOMPLETED: '未完成'
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/constants.js:
--------------------------------------------------------------------------------
1 | export const FilterTypes = {
2 | ALL: '全部',
3 | COMPLETED: '已完成',
4 | UNCOMPLETED: '未完成'
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-11/chunked_with_redux/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-11/react_router_basic/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-11/react_router_basic/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/constants.js:
--------------------------------------------------------------------------------
1 | export const FilterTypes = {
2 | ALL: '全部',
3 | COMPLETED: '已完成',
4 | UNCOMPLETED: '未完成'
5 | }
6 |
7 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux/src/weather/status.js:
--------------------------------------------------------------------------------
1 | export const LOADING = 'loading';
2 | export const SUCCESS = 'success';
3 | export const FAILURE = 'failure';
4 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux_improved/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-07/weather_redux_improved/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-11/react_router_chunked/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-11/react_router_chunked/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-02/controlpanel_with_summary/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-02/controlpanel_with_summary/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-04/todo_controlled_component/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-07/weather_redux/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
7 | div {
8 | margin: 10px;
9 | }
10 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux_improved/src/weather/status.js:
--------------------------------------------------------------------------------
1 | export const LOADING = 'loading';
2 | export const SUCCESS = 'success';
3 | export const FAILURE = 'failure';
4 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/components/Counter/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const INCREMENT = 'counter/increment';
2 |
3 | export const DECREMENT = 'counter/decrement';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/components/Counter/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const INCREMENT = 'counter/increment';
2 |
3 | export const DECREMENT = 'counter/decrement';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/todos/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const ADD_TODO = 'TODO/ADD';
2 | export const TOGGLE_TODO = 'TODO/TOGGLE';
3 | export const REMOVE_TODO = 'TODO/REMOVE';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/src/weather/status.js:
--------------------------------------------------------------------------------
1 | export const LOADING = 'loading';
2 | export const SUCCESS = 'success';
3 | export const FAILURE = 'failure';
4 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/components/Counter/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const INCREMENT = 'counter/increment';
2 |
3 | export const DECREMENT = 'counter/decrement';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/todos/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const ADD_TODO = 'TODO/ADD';
2 | export const TOGGLE_TODO = 'TODO/TOGGLE';
3 | export const REMOVE_TODO = 'TODO/REMOVE';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux_improved/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
7 | div {
8 | margin: 10px;
9 | }
10 |
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mocheng/react-and-redux/HEAD/chapter-09/weather_with_promise_middleware/public/favicon.ico
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/todos/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const ADD_TODO = 'TODO/ADD';
2 | export const TOGGLE_TODO = 'TODO/TOGGLE';
3 | export const REMOVE_TODO = 'TODO/REMOVE';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/todos/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const ADD_TODO = 'TODO/ADD';
2 | export const TOGGLE_TODO = 'TODO/TOGGLE';
3 | export const REMOVE_TODO = 'TODO/REMOVE';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
7 | div {
8 | margin: 10px;
9 | }
10 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/todos/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const ADD_TODO = 'TODO/ADD';
2 | export const TOGGLE_TODO = 'TODO/TOGGLE';
3 | export const REMOVE_TODO = 'TODO/REMOVE';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/filter/actions.js:
--------------------------------------------------------------------------------
1 | import {SET_FILTER} from './actionTypes.js';
2 |
3 | export const setFilter = filterType => ({
4 | type: SET_FILTER,
5 | filter: filterType
6 | });
7 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/todos/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const ADD_TODO = 'TODO/ADD';
2 | export const TOGGLE_TODO = 'TODO/TOGGLE';
3 | export const REMOVE_TODO = 'TODO/REMOVE';
4 |
5 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/todos/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './views/todos.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/filter/actions.js:
--------------------------------------------------------------------------------
1 | import {SET_FILTER} from './actionTypes.js';
2 |
3 | export const setFilter = filterType => ({
4 | type: SET_FILTER,
5 | filter: filterType
6 | });
7 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/filter/actions.js:
--------------------------------------------------------------------------------
1 | import {SET_FILTER} from './actionTypes.js';
2 |
3 | export const setFilter = filterType => ({
4 | type: SET_FILTER,
5 | filter: filterType
6 | });
7 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/pages/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const About = () => {
4 | return (
5 |
About
6 | );
7 | };
8 |
9 | export default About;
10 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/pages/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const About = () => {
4 | return (
5 | About
6 | );
7 | };
8 |
9 | export default About;
10 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/filter/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './views/filters.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/todos/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './views/todos.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/filter/actions.js:
--------------------------------------------------------------------------------
1 | import {SET_FILTER} from './actionTypes.js';
2 |
3 | export const setFilter = filterType => ({
4 | type: SET_FILTER,
5 | filter: filterType
6 | });
7 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux/src/weather/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './view.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/filter/actions.js:
--------------------------------------------------------------------------------
1 | import {SET_FILTER} from './actionTypes.js';
2 |
3 | export const setFilter = filterType => ({
4 | type: SET_FILTER,
5 | filter: filterType
6 | });
7 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/pages/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const About = () => {
4 | return (
5 | About
6 | );
7 | };
8 |
9 | export default About;
10 |
--------------------------------------------------------------------------------
/chapter-11/react_router_basic/src/pages/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const About = () => {
4 | return (
5 | About
6 | );
7 | };
8 |
9 | export default About;
10 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/filter/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './views/filters.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/todos/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './views/todos.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-11/react_router_chunked/src/pages/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const About = () => {
4 | return (
5 | About
6 | );
7 | };
8 |
9 | export default About;
10 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/filter/actions.js:
--------------------------------------------------------------------------------
1 | import {SET_FILTER} from './actionTypes.js';
2 |
3 | export const setFilter = filterType => ({
4 | type: SET_FILTER,
5 | filter: filterType
6 | });
7 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/todos/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './views/todos.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux_improved/src/weather/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './view.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/filter/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './views/filters.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/filter/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './views/filters.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/todos/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './views/todos.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/pages/NotFound.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const NotFound = () => {
4 | return (
5 | 404: Not Found
6 | );
7 | };
8 |
9 | export default NotFound;
10 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/todos/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './views/todos.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/filter/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './views/filters.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/pages/NotFound.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const NotFound = () => {
4 | return (
5 | 404: Not Found
6 | );
7 | };
8 |
9 | export default NotFound;
10 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/filter/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './views/filters.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux/src/weather/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const FETCH_STARTED = 'WEATHER/FETCH_STARTED';
2 | export const FETCH_SUCCESS = 'WEATHER/FETCH_SUCCESS';
3 | export const FETCH_FAILURE = 'WEATHER/FETCH_FAILURE';
4 |
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/src/weather/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view from './view.js';
4 |
5 | export {actions, reducer, view};
6 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/pages/NotFound.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const NotFound = () => {
4 | return (
5 | 404: Not Found
6 | );
7 | };
8 |
9 | export default NotFound;
10 |
--------------------------------------------------------------------------------
/chapter-11/react_router_basic/src/pages/NotFound.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const NotFound = () => {
4 | return (
5 | 404: Not Found
6 | );
7 | };
8 |
9 | export default NotFound;
10 |
--------------------------------------------------------------------------------
/chapter-11/react_router_chunked/src/pages/NotFound.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const NotFound = () => {
4 | return (
5 | 404: Not Found
6 | );
7 | };
8 |
9 | export default NotFound;
10 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux_improved/src/weather/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const FETCH_STARTED = 'WEATHER/FETCH_STARTED';
2 | export const FETCH_SUCCESS = 'WEATHER/FETCH_SUCCESS';
3 | export const FETCH_FAILURE = 'WEATHER/FETCH_FAILURE';
4 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/components/Counter/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view, {stateKey} from './view.js';
4 |
5 | export {actions, reducer, view, stateKey};
6 |
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/src/weather/actionTypes.js:
--------------------------------------------------------------------------------
1 | export const FETCH_STARTED = 'WEATHER/FETCH_STARTED';
2 | export const FETCH_SUCCESS = 'WEATHER/FETCH_SUCCESS';
3 | export const FETCH_FAILURE = 'WEATHER/FETCH_FAILURE';
4 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/components/Counter/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view, {stateKey} from './view.js';
4 |
5 | export {actions, reducer, view, stateKey};
6 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/components/Counter/index.js:
--------------------------------------------------------------------------------
1 | import * as actions from './actions.js';
2 | import reducer from './reducer.js';
3 | import view, {stateKey} from './view.js';
4 |
5 | export {actions, reducer, view, stateKey};
6 |
--------------------------------------------------------------------------------
/chapter-01/jquery_solution/clickCounter.js:
--------------------------------------------------------------------------------
1 | $(function() {
2 | $('#clickMe').click(function() {
3 | var clickCounter = $('#clickCount');
4 | var count = parseInt(clickCounter.text(), 10);
5 | clickCounter.text(count+1);
6 | })
7 | })
8 |
--------------------------------------------------------------------------------
/chapter-07/weather_react/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import Weather from './Weather';
4 | import './index.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/chapter-05/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/chapter-01/first_react_app/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render( , div);
8 | });
9 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import ControlPanel from './ControlPanel';
4 | import './index.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/chapter-03/flux/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/chapter-03/flux/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import ControlPanel from './views/ControlPanel';
4 | import './index.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/chapter-04/todo/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/chapter-01/first_react_app/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import ClickCounter from './ClickCounter';
4 | import './index.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/chapter-03/redux_basic/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import ControlPanel from './views/ControlPanel';
4 | import './index.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/components/Counter/actions.js:
--------------------------------------------------------------------------------
1 | import * as ActionTypes from './actionTypes.js';
2 |
3 | export const increment = () => ({
4 | type: ActionTypes.INCREMENT
5 | });
6 |
7 | export const decrement = () => ({
8 | type: ActionTypes.DECREMENT
9 | });
10 |
--------------------------------------------------------------------------------
/chapter-01/first_react_app/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/chapter-03/redux_smart_dumb/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import ControlPanel from './views/ControlPanel';
4 | import './index.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/chapter-07/weather_react/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/components/Counter/actions.js:
--------------------------------------------------------------------------------
1 | import * as ActionTypes from './actionTypes.js';
2 |
3 | export const increment = () => ({
4 | type: ActionTypes.INCREMENT
5 | });
6 |
7 | export const decrement = () => ({
8 | type: ActionTypes.DECREMENT
9 | });
10 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel_with_summary/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import ControlPanel from './ControlPanel';
4 | import './index.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/components/Counter/actions.js:
--------------------------------------------------------------------------------
1 | import * as ActionTypes from './actionTypes.js';
2 |
3 | export const increment = () => ({
4 | type: ActionTypes.INCREMENT
5 | });
6 |
7 | export const decrement = () => ({
8 | type: ActionTypes.DECREMENT
9 | });
10 |
--------------------------------------------------------------------------------
/chapter-11/react_router_basic/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel_with_summary/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux_improved/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | node_modules
5 |
6 | # testing
7 | coverage
8 |
9 | # production
10 | build
11 |
12 | # misc
13 | .DS_Store
14 | .env
15 | npm-debug.log
16 |
--------------------------------------------------------------------------------
/chapter-03/react-redux/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore} from 'redux';
2 | import reducer from './Reducer.js';
3 |
4 | const initValues = {
5 | 'First': 0,
6 | 'Second': 10,
7 | 'Third': 20
8 | };
9 |
10 | const store = createStore(reducer, initValues);
11 |
12 | export default store;
13 |
--------------------------------------------------------------------------------
/chapter-03/redux_basic/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore} from 'redux';
2 | import reducer from './Reducer.js';
3 |
4 | const initValues = {
5 | 'First': 0,
6 | 'Second': 10,
7 | 'Third': 20
8 | };
9 |
10 | const store = createStore(reducer, initValues);
11 |
12 | export default store;
13 |
--------------------------------------------------------------------------------
/chapter-03/redux_smart_dumb/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore} from 'redux';
2 | import reducer from './Reducer.js';
3 |
4 | const initValues = {
5 | 'First': 0,
6 | 'Second': 10,
7 | 'Third': 20
8 | };
9 |
10 | const store = createStore(reducer, initValues);
11 |
12 | export default store;
13 |
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore} from 'redux';
2 | import reducer from './Reducer.js';
3 |
4 | const initValues = {
5 | 'First': 0,
6 | 'Second': 10,
7 | 'Third': 20
8 | };
9 |
10 | const store = createStore(reducer, initValues);
11 |
12 | export default store;
13 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/TodoApp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {view as Todos} from './todos/';
3 | import {view as Filter} from './filter/';
4 |
5 | function TodoApp() {
6 | return (
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default TodoApp;
15 |
--------------------------------------------------------------------------------
/chapter-06/hoc/src/proxy/removeUserPropHOC.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function removeUserProp(WrappedComponent) {
4 | return function newRender(props) {
5 | const {user, ...otherProps} = props;
6 | return
7 | }
8 | }
9 |
10 | export default removeUserProp;
11 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/pages/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {view as TopMenu} from '../components/TopMenu';
4 |
5 | const App = ({children}) => {
6 | return (
7 |
11 | );
12 | };
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/TodoApp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {view as Todos} from './todos/';
3 | import {view as Filter} from './filter/';
4 |
5 | function TodoApp() {
6 | return (
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default TodoApp;
15 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/TodoApp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {view as Todos} from './todos/';
3 | import {view as Filter} from './filter/';
4 |
5 | function TodoApp() {
6 | return (
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default TodoApp;
15 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/pages/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {view as TopMenu} from '../components/TopMenu';
4 |
5 | const App = ({children}) => {
6 | return (
7 |
11 | );
12 | };
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/chapter-11/react_router_basic/src/pages/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {view as TopMenu} from '../components/TopMenu';
4 |
5 | const App = ({children}) => {
6 | return (
7 |
11 | );
12 | };
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/pages/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {view as TopMenu} from '../components/TopMenu';
4 |
5 | const App = ({children}) => {
6 | return (
7 |
11 | );
12 | };
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/TodoApp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {view as Todos} from './todos/';
3 | import {view as Filter} from './filter/';
4 |
5 | function TodoApp() {
6 | return (
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default TodoApp;
15 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/TodoApp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {view as Todos} from './todos/';
3 | import {view as Filter} from './filter/';
4 |
5 | function TodoApp() {
6 | return (
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default TodoApp;
15 |
--------------------------------------------------------------------------------
/chapter-11/react_router_chunked/src/pages/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {view as TopMenu} from '../components/TopMenu';
4 |
5 | const App = ({children}) => {
6 | return (
7 |
11 | );
12 | };
13 |
14 | export default App;
15 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/TodoApp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {view as Todos} from './todos/';
3 | import {view as Filter} from './filter/';
4 |
5 | function TodoApp() {
6 | return (
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default TodoApp;
15 |
--------------------------------------------------------------------------------
/chapter-06/hoc/src/inheritance/cacheHOC.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const cacheHOC = (WrappedComponent) => {
4 | return class NewComponent extends WrappedComponent {
5 | shouldComponentUpdate(nextProps, nextState) {
6 | return nextProps.useCache;
7 | }
8 | }
9 | }
10 |
11 | export default onlyForLoggedinHOC;
12 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/filter/reducer.js:
--------------------------------------------------------------------------------
1 | import {SET_FILTER} from './actionTypes.js';
2 | import {FilterTypes} from '../constants.js'
3 |
4 | export default (state = FilterTypes.ALL, action) => {
5 | switch(action.type) {
6 | case SET_FILTER: {
7 | return action.filter;
8 | }
9 | default:
10 | return state;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/todos/views/todos.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import AddTodo from './addTodo.js';
3 | import TodoList from './todoList.js';
4 |
5 | import './style.css';
6 |
7 | export default () => {
8 | return (
9 |
13 | );
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/chapter-06/hoc/src/proxy/AddNewPropsHOC.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const addNewProps = (WrappedComponent, newProps) => {
4 | return class WrappingComponent extends React.Component {
5 | render() {
6 | return
7 | }
8 | }
9 | }
10 |
11 | export default addNewProps;
12 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/filter/reducer.js:
--------------------------------------------------------------------------------
1 | import {SET_FILTER} from './actionTypes.js';
2 | import {FilterTypes} from '../constants.js'
3 |
4 | export default (state = FilterTypes.ALL, action) => {
5 | switch(action.type) {
6 | case SET_FILTER: {
7 | return action.filter;
8 | }
9 | default:
10 | return state;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/todos/views/todos.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import AddTodo from './addTodo.js';
3 | import TodoList from './todoList.js';
4 |
5 | import './style.css';
6 |
7 | export default () => {
8 | return (
9 |
13 | );
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/todos/views/todos.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import AddTodo from './addTodo.js';
3 | import TodoList from './todoList.js';
4 |
5 | import './style.css';
6 |
7 | export default () => {
8 | return (
9 |
13 | );
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/components/Counter/reducer.js:
--------------------------------------------------------------------------------
1 | import {INCREMENT, DECREMENT} from './actionTypes.js';
2 |
3 | export default (state = {}, action) => {
4 | switch (action.type) {
5 | case INCREMENT:
6 | return state + 1;
7 | case DECREMENT:
8 | return state - 1;
9 | default:
10 | return state
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/components/Counter/reducer.js:
--------------------------------------------------------------------------------
1 | import {INCREMENT, DECREMENT} from './actionTypes.js';
2 |
3 | export default (state = {}, action) => {
4 | switch (action.type) {
5 | case INCREMENT:
6 | return state + 1;
7 | case DECREMENT:
8 | return state - 1;
9 | default:
10 | return state
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Provider} from 'react-redux';
4 | import TodoApp from './TodoApp';
5 |
6 | import store from './Store.js';
7 |
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById('root')
13 | );
14 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/todos/views/todos.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import AddTodo from './addTodo.js';
3 | import TodoList from './todoList.js';
4 |
5 | import './style.css';
6 |
7 | export default () => {
8 | return (
9 |
13 | );
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/filter/reducer.js:
--------------------------------------------------------------------------------
1 | import {SET_FILTER} from './actionTypes.js';
2 | import {FilterTypes} from '../constants.js'
3 |
4 | export default (state = FilterTypes.ALL, action) => {
5 | switch(action.type) {
6 | case SET_FILTER: {
7 | return action.filter;
8 | }
9 | default:
10 | return state;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/todos/views/todos.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import AddTodo from './addTodo.js';
3 | import TodoList from './todoList.js';
4 |
5 | import './style.css';
6 |
7 | export default () => {
8 | return (
9 |
13 | );
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/components/Counter/reducer.js:
--------------------------------------------------------------------------------
1 | import {INCREMENT, DECREMENT} from './actionTypes.js';
2 |
3 | export default (state = {}, action) => {
4 | switch (action.type) {
5 | case INCREMENT:
6 | return state + 1;
7 | case DECREMENT:
8 | return state - 1;
9 | default:
10 | return state
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Provider} from 'react-redux';
4 | import TodoApp from './TodoApp';
5 |
6 | import store from './Store.js';
7 |
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById('root')
13 | );
14 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/filter/reducer.js:
--------------------------------------------------------------------------------
1 | import {SET_FILTER} from './actionTypes.js';
2 | import {FilterTypes} from '../constants.js'
3 |
4 | export default (state = FilterTypes.ALL, action) => {
5 | switch(action.type) {
6 | case SET_FILTER: {
7 | return action.filter;
8 | }
9 | default:
10 | return state;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/todos/views/todoItem.css:
--------------------------------------------------------------------------------
1 | .fade-enter{
2 | opacity: 0.01;
3 | }
4 |
5 | .fade-enter.fade-enter-active {
6 | opacity: 1;
7 | transition: opacity 500ms ease-in;
8 | }
9 |
10 | .fade-leave {
11 | opacity: 1;
12 | }
13 |
14 | .fade-leave.fade-leave-active {
15 | opacity: 0.01;
16 | transition: opacity 200ms ease-in;
17 | }
18 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/filter/reducer.js:
--------------------------------------------------------------------------------
1 | import {SET_FILTER} from './actionTypes.js';
2 | import {FilterTypes} from '../constants.js'
3 |
4 | export default (state = FilterTypes.ALL, action) => {
5 | switch(action.type) {
6 | case SET_FILTER: {
7 | return action.filter;
8 | }
9 | default:
10 | return state;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/filter/reducer.js:
--------------------------------------------------------------------------------
1 | import {SET_FILTER} from './actionTypes.js';
2 | import {FilterTypes} from '../constants.js'
3 |
4 | export default (state = FilterTypes.ALL, action) => {
5 | switch(action.type) {
6 | case SET_FILTER: {
7 | return action.filter;
8 | }
9 | default:
10 | return state;
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/todos/views/todos.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import AddTodo from './addTodo.js';
3 | import TodoList from './todoList.js';
4 |
5 | import './style.css';
6 |
7 | export default () => {
8 | return (
9 |
13 | );
14 | }
15 |
16 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Provider} from 'react-redux';
4 | import TodoApp from './TodoApp';
5 |
6 | import store from './Store.js';
7 |
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById('root')
13 | );
14 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Provider} from 'react-redux';
4 | import TodoApp from './TodoApp';
5 |
6 | import store from './Store.js';
7 |
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById('root')
13 | );
14 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Provider} from 'react-redux';
4 | import TodoApp from './TodoApp';
5 |
6 | import store from './Store.js';
7 |
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById('root')
13 | );
14 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Provider} from 'react-redux';
4 | import TodoApp from './TodoApp';
5 |
6 | import store from './Store.js';
7 |
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById('root')
13 | );
14 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | // This is a custom Jest transformer turning file imports into filenames.
4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
5 |
6 | module.exports = {
7 | process(src, filename) {
8 | return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Provider} from 'react-redux';
4 | import App from './App.js';
5 |
6 | import './index.css';
7 |
8 | import store from './Store.js'
9 |
10 | ReactDOM.render(
11 |
12 |
13 | ,
14 | document.getElementById('root')
15 | );
16 |
--------------------------------------------------------------------------------
/chapter-12/express_server/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | // This is a custom Jest transformer turning file imports into filenames.
4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
5 |
6 | module.exports = {
7 | process(src, filename) {
8 | return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux_improved/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Provider} from 'react-redux';
4 | import App from './App.js';
5 |
6 | import './index.css';
7 |
8 | import store from './Store.js'
9 |
10 | ReactDOM.render(
11 |
12 |
13 | ,
14 | document.getElementById('root')
15 | );
16 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | // This is a custom Jest transformer turning file imports into filenames.
4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
5 |
6 | module.exports = {
7 | process(src, filename) {
8 | return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/pages/CounterPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {view as Counter, stateKey, reducer} from '../components/Counter';
3 |
4 | const page = () => {
5 | return (
6 |
10 | );
11 | };
12 |
13 | const initialState = 100;
14 |
15 | export {page, reducer, initialState, stateKey};
16 |
--------------------------------------------------------------------------------
/chapter-11/react_router_chunked/config/jest/fileTransform.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | // This is a custom Jest transformer turning file imports into filenames.
4 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
5 |
6 | module.exports = {
7 | process(src, filename) {
8 | return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
9 | },
10 | };
11 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | import Routes from './Routes.js';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
11 | /*
12 | ReactDOM.render(
13 |
14 | ,
15 |
16 | document.getElementById('root')
17 | );
18 | */
19 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | import Routes from './Routes.js';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
11 | /*
12 | ReactDOM.render(
13 |
14 | ,
15 |
16 | document.getElementById('root')
17 | );
18 | */
19 |
--------------------------------------------------------------------------------
/chapter-11/react_router_basic/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | import Routes from './Routes.js';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
11 | /*
12 | ReactDOM.render(
13 |
14 | ,
15 |
16 | document.getElementById('root')
17 | );
18 | */
19 |
--------------------------------------------------------------------------------
/chapter-06/hoc/src/proxy/StyleHOC.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const styleHOC = (WrappedComponent, style) => {
4 | return class HOCComponent extends React.Component {
5 | render() {
6 | return (
7 |
8 |
9 |
10 | );
11 | }
12 | };
13 | };
14 |
15 | export default styleHOC;
16 |
17 |
18 |
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Provider} from 'react-redux';
4 | import App from './App.js';
5 |
6 | import './index.css';
7 |
8 | import store from './Store.js'
9 |
10 | ReactDOM.render(
11 |
12 |
13 | ,
14 | document.getElementById('root')
15 | );
16 |
--------------------------------------------------------------------------------
/chapter-11/react_router_chunked/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 |
4 | import Routes from './Routes.js';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
11 | /*
12 | ReactDOM.render(
13 |
14 | ,
15 |
16 | document.getElementById('root')
17 | );
18 | */
19 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {connect} from 'react-redux';
3 |
4 | const Home = ({greetings}) => {
5 | return (
6 |
7 |
Home
8 |
{greetings}
9 |
10 | );
11 | };
12 |
13 | const mapStateToProps = (state) => ({greetings: state.greetings});
14 |
15 | export default connect(mapStateToProps)(Home);
16 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {connect} from 'react-redux';
3 |
4 | const Home = ({greetings}) => {
5 | return (
6 |
7 |
Home
8 |
{greetings}
9 |
10 | );
11 | };
12 |
13 | const mapStateToProps = (state) => ({greetings: state.greetings});
14 |
15 | export default connect(mapStateToProps)(Home);
16 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | import {view as CitySelector} from './city_selector/';
4 | import {view as Weather} from './weather/';
5 |
6 | class App extends Component {
7 | render() {
8 | return (
9 |
10 |
11 |
12 |
13 | );
14 | }
15 | }
16 |
17 | export default App;
18 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {connect} from 'react-redux';
3 |
4 | const Home = ({greetings}) => {
5 | return (
6 |
7 |
Home
8 |
{greetings}
9 |
10 | );
11 | };
12 |
13 | const mapStateToProps = (state) => ({greetings: state.greetings});
14 |
15 | export default connect(mapStateToProps)(Home);
16 |
--------------------------------------------------------------------------------
/chapter-11/react_router_basic/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {connect} from 'react-redux';
3 |
4 | const Home = ({greetings}) => {
5 | return (
6 |
7 |
Home
8 |
{greetings}
9 |
10 | );
11 | };
12 |
13 | const mapStateToProps = (state) => ({greetings: state.greetings});
14 |
15 | export default connect(mapStateToProps)(Home);
16 |
--------------------------------------------------------------------------------
/chapter-03/react-redux/src/Actions.js:
--------------------------------------------------------------------------------
1 | import * as ActionTypes from './ActionTypes.js';
2 |
3 | export const increment = (counterCaption) => {
4 | return {
5 | type: ActionTypes.INCREMENT,
6 | counterCaption: counterCaption
7 | };
8 | };
9 |
10 | export const decrement = (counterCaption) => {
11 | return {
12 | type: ActionTypes.DECREMENT,
13 | counterCaption: counterCaption
14 | };
15 | };
16 |
--------------------------------------------------------------------------------
/chapter-03/react-redux/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import {Provider} from 'react-redux';
4 |
5 | import ControlPanel from './views/ControlPanel';
6 | import store from './Store.js';
7 |
8 | import './index.css';
9 |
10 | ReactDOM.render(
11 |
12 |
13 | ,
14 | document.getElementById('root')
15 | );
16 |
--------------------------------------------------------------------------------
/chapter-03/redux_basic/src/Actions.js:
--------------------------------------------------------------------------------
1 | import * as ActionTypes from './ActionTypes.js';
2 |
3 | export const increment = (counterCaption) => {
4 | return {
5 | type: ActionTypes.INCREMENT,
6 | counterCaption: counterCaption
7 | };
8 | };
9 |
10 | export const decrement = (counterCaption) => {
11 | return {
12 | type: ActionTypes.DECREMENT,
13 | counterCaption: counterCaption
14 | };
15 | };
16 |
--------------------------------------------------------------------------------
/chapter-06/hoc/src/inheritance/OnlyForLoggedinHOC.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const onlyForLoggedinHOC = (WrappedComponent) => {
4 | return class NewComponent extends WrappedComponent {
5 | render() {
6 | if (this.props.loggedIn) {
7 | return super.render();
8 | } else {
9 | return null;
10 | }
11 | }
12 | }
13 | }
14 |
15 | export default onlyForLoggedinHOC;
16 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux_improved/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | import {view as CitySelector} from './city_selector/';
4 | import {view as Weather} from './weather/';
5 |
6 | class App extends Component {
7 | render() {
8 | return (
9 |
10 |
11 |
12 |
13 | );
14 | }
15 | }
16 |
17 | export default App;
18 |
--------------------------------------------------------------------------------
/chapter-11/react_router_chunked/src/pages/Home.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {connect} from 'react-redux';
3 |
4 | const Home = ({greetings}) => {
5 | return (
6 |
7 |
Home
8 |
{greetings}
9 |
10 | );
11 | };
12 |
13 | const mapStateToProps = (state) => ({greetings: state.greetings});
14 |
15 | export default connect(mapStateToProps)(Home);
16 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | // This is a custom Jest transformer turning style imports into empty objects.
2 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
3 |
4 | module.exports = {
5 | process() {
6 | return 'module.exports = {};';
7 | },
8 | getCacheKey(fileData, filename) {
9 | // The output is always the same.
10 | return 'cssTransform';
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/chapter-01/jquery_solution/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Click Me
6 |
7 | Click Count: 0
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/chapter-03/redux_smart_dumb/src/Actions.js:
--------------------------------------------------------------------------------
1 | import * as ActionTypes from './ActionTypes.js';
2 |
3 | export const increment = (counterCaption) => {
4 | return {
5 | type: ActionTypes.INCREMENT,
6 | counterCaption: counterCaption
7 | };
8 | };
9 |
10 | export const decrement = (counterCaption) => {
11 | return {
12 | type: ActionTypes.DECREMENT,
13 | counterCaption: counterCaption
14 | };
15 | };
16 |
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import ControlPanel from './views/ControlPanel';
4 | import './index.css';
5 |
6 | import store from './Store.js';
7 | import Provider from './Provider.js';
8 |
9 | ReactDOM.render(
10 |
11 |
12 | ,
13 | document.getElementById('root')
14 | );
15 |
--------------------------------------------------------------------------------
/chapter-06/function_as_child/src/AddUserProp.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const loggedinUser = 'mock user';
4 |
5 | class AddUserProp extends React.Component {
6 | render() {
7 | const user = loggedinUser;
8 | return this.props.children(user)
9 | }
10 | }
11 |
12 | AddUserProp.propTypes = {
13 | children: React.PropTypes.func.isRequired
14 | }
15 |
16 | export default AddUserProp;
17 |
18 |
19 |
--------------------------------------------------------------------------------
/chapter-12/express_server/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | // This is a custom Jest transformer turning style imports into empty objects.
2 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
3 |
4 | module.exports = {
5 | process() {
6 | return 'module.exports = {};';
7 | },
8 | getCacheKey(fileData, filename) {
9 | // The output is always the same.
10 | return 'cssTransform';
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/pages/CounterPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {view as Counter, stateKey, reducer} from '../components/Counter';
3 |
4 | const page = () => {
5 | return (
6 |
10 | );
11 | };
12 |
13 | const initState = () => Promise.resolve(100);
14 |
15 | export {page, reducer, initState, stateKey};
16 |
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/src/Actions.js:
--------------------------------------------------------------------------------
1 | import * as ActionTypes from './ActionTypes.js';
2 |
3 | export const increment = (counterCaption) => {
4 | return {
5 | type: ActionTypes.INCREMENT,
6 | counterCaption: counterCaption
7 | };
8 | };
9 |
10 | export const decrement = (counterCaption) => {
11 | return {
12 | type: ActionTypes.DECREMENT,
13 | counterCaption: counterCaption
14 | };
15 | };
16 |
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | import {view as CitySelector} from './city_selector/';
4 | import {view as Weather} from './weather/';
5 |
6 | class App extends Component {
7 | render() {
8 | return (
9 |
10 |
11 |
12 |
13 | );
14 | }
15 | }
16 |
17 | export default App;
18 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | // This is a custom Jest transformer turning style imports into empty objects.
2 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
3 |
4 | module.exports = {
5 | process() {
6 | return 'module.exports = {};';
7 | },
8 | getCacheKey(fileData, filename) {
9 | // The output is always the same.
10 | return 'cssTransform';
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/chapter-11/react_router_chunked/config/jest/cssTransform.js:
--------------------------------------------------------------------------------
1 | // This is a custom Jest transformer turning style imports into empty objects.
2 | // http://facebook.github.io/jest/docs/tutorial-webpack.html
3 |
4 | module.exports = {
5 | process() {
6 | return 'module.exports = {};';
7 | },
8 | getCacheKey(fileData, filename) {
9 | // The output is always the same.
10 | return 'cssTransform';
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/todos/actions.js:
--------------------------------------------------------------------------------
1 | import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO} from './actionTypes.js';
2 |
3 | let nextTodoId = 0;
4 |
5 | export const addTodo = (text) => ({
6 | type: ADD_TODO,
7 | completed: false,
8 | id: nextTodoId ++,
9 | text: text
10 | });
11 |
12 | export const toggleTodo = (id) => ({
13 | type: TOGGLE_TODO,
14 | id: id
15 | });
16 |
17 | export const removeTodo = (id) => ({
18 | type: REMOVE_TODO,
19 | id: id
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/chapter-03/react-redux/src/Reducer.js:
--------------------------------------------------------------------------------
1 | import * as ActionTypes from './ActionTypes.js';
2 |
3 | export default (state, action) => {
4 | const {counterCaption} = action;
5 |
6 | switch (action.type) {
7 | case ActionTypes.INCREMENT:
8 | return {...state, [counterCaption]: state[counterCaption] + 1};
9 | case ActionTypes.DECREMENT:
10 | return {...state, [counterCaption]: state[counterCaption] - 1};
11 | default:
12 | return state
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/chapter-03/redux_basic/src/Reducer.js:
--------------------------------------------------------------------------------
1 | import * as ActionTypes from './ActionTypes.js';
2 |
3 | export default (state, action) => {
4 | const {counterCaption} = action;
5 |
6 | switch (action.type) {
7 | case ActionTypes.INCREMENT:
8 | return {...state, [counterCaption]: state[counterCaption] + 1};
9 | case ActionTypes.DECREMENT:
10 | return {...state, [counterCaption]: state[counterCaption] - 1};
11 | default:
12 | return state
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/todos/actions.js:
--------------------------------------------------------------------------------
1 | import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO} from './actionTypes.js';
2 |
3 | let nextTodoId = 10;
4 |
5 | export const addTodo = (text) => ({
6 | type: ADD_TODO,
7 | completed: false,
8 | id: nextTodoId ++,
9 | text: text
10 | });
11 |
12 | export const toggleTodo = (id) => ({
13 | type: TOGGLE_TODO,
14 | id: id
15 | });
16 |
17 | export const removeTodo = (id) => ({
18 | type: REMOVE_TODO,
19 | id: id
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/chapter-01/first_react_app/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 80px;
8 | }
9 |
10 | .App-header {
11 | background-color: #222;
12 | height: 150px;
13 | padding: 20px;
14 | color: white;
15 | }
16 |
17 | .App-intro {
18 | font-size: large;
19 | }
20 |
21 | @keyframes App-logo-spin {
22 | from { transform: rotate(0deg); }
23 | to { transform: rotate(360deg); }
24 | }
25 |
--------------------------------------------------------------------------------
/chapter-03/redux_smart_dumb/src/Reducer.js:
--------------------------------------------------------------------------------
1 | import * as ActionTypes from './ActionTypes.js';
2 |
3 | export default (state, action) => {
4 | const {counterCaption} = action;
5 |
6 | switch (action.type) {
7 | case ActionTypes.INCREMENT:
8 | return {...state, [counterCaption]: state[counterCaption] + 1};
9 | case ActionTypes.DECREMENT:
10 | return {...state, [counterCaption]: state[counterCaption] - 1};
11 | default:
12 | return state
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/todos/actions.js:
--------------------------------------------------------------------------------
1 | import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO} from './actionTypes.js';
2 |
3 | let nextTodoId = 10;
4 |
5 | export const addTodo = (text) => ({
6 | type: ADD_TODO,
7 | completed: false,
8 | id: nextTodoId ++,
9 | text: text
10 | });
11 |
12 | export const toggleTodo = (id) => ({
13 | type: TOGGLE_TODO,
14 | id: id
15 | });
16 |
17 | export const removeTodo = (id) => ({
18 | type: REMOVE_TODO,
19 | id: id
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/src/Reducer.js:
--------------------------------------------------------------------------------
1 | import * as ActionTypes from './ActionTypes.js';
2 |
3 | export default (state, action) => {
4 | const {counterCaption} = action;
5 |
6 | switch (action.type) {
7 | case ActionTypes.INCREMENT:
8 | return {...state, [counterCaption]: state[counterCaption] + 1};
9 | case ActionTypes.DECREMENT:
10 | return {...state, [counterCaption]: state[counterCaption] - 1};
11 | default:
12 | return state
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/todos/actions.js:
--------------------------------------------------------------------------------
1 | import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO} from './actionTypes.js';
2 |
3 | let nextTodoId = 10;
4 |
5 | export const addTodo = (text) => ({
6 | type: ADD_TODO,
7 | completed: false,
8 | id: nextTodoId ++,
9 | text: text
10 | });
11 |
12 | export const toggleTodo = (id) => ({
13 | type: TOGGLE_TODO,
14 | id: id
15 | });
16 |
17 | export const removeTodo = (id) => ({
18 | type: REMOVE_TODO,
19 | id: id
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/chapter-09/reset_enhancer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "react": "^15.4.1",
7 | "react-addons-test-utils": "^15.4.1",
8 | "react-dom": "^15.4.1",
9 | "react-redux": "^5.0.1",
10 | "react-scripts": "0.8.4",
11 | "redux": "^3.6.0",
12 | "sinon": "^1.17.7"
13 | },
14 | "dependencies": {},
15 | "scripts": {
16 | "test": "react-scripts test --env=jsdom"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/chapter-10/animation_types/css3_sample.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/todos/actions.js:
--------------------------------------------------------------------------------
1 | import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO} from './actionTypes.js';
2 |
3 | let nextTodoId = 10;
4 |
5 | export const addTodo = (text) => ({
6 | type: ADD_TODO,
7 | completed: false,
8 | id: nextTodoId ++,
9 | text: text
10 | });
11 |
12 | export const toggleTodo = (id) => ({
13 | type: TOGGLE_TODO,
14 | id: id
15 | });
16 |
17 | export const removeTodo = (id) => ({
18 | type: REMOVE_TODO,
19 | id: id
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/chapter-03/flux/src/Actions.js:
--------------------------------------------------------------------------------
1 | import * as ActionTypes from './ActionTypes.js';
2 | import AppDispatcher from './AppDispatcher.js';
3 |
4 | export const increment = (counterCaption) => {
5 | AppDispatcher.dispatch({
6 | type: ActionTypes.INCREMENT,
7 | counterCaption: counterCaption
8 | });
9 | };
10 |
11 | export const decrement = (counterCaption) => {
12 | AppDispatcher.dispatch({
13 | type: ActionTypes.DECREMENT,
14 | counterCaption: counterCaption
15 | });
16 | };
17 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/todos/actions.js:
--------------------------------------------------------------------------------
1 | import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO} from './actionTypes.js';
2 |
3 | let nextTodoId = 0;
4 |
5 | export const addTodo = (text) => ({
6 | type: ADD_TODO,
7 | completed: false,
8 | id: nextTodoId ++,
9 | text: text
10 | });
11 |
12 | export const toggleTodo = (id) => ({
13 | type: TOGGLE_TODO,
14 | id: id
15 | });
16 |
17 | export const removeTodo = (id) => ({
18 | type: REMOVE_TODO,
19 | id: id
20 | });
21 |
22 |
--------------------------------------------------------------------------------
/chapter-09/promise_middleware/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "react": "^15.4.1",
7 | "react-addons-test-utils": "^15.4.1",
8 | "react-dom": "^15.4.1",
9 | "react-redux": "^5.0.1",
10 | "react-scripts": "0.8.4",
11 | "redux": "^3.6.0",
12 | "sinon": "^1.17.7"
13 | },
14 | "dependencies": {},
15 | "scripts": {
16 | "test": "react-scripts test --env=jsdom"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/chapter-11/react_router_basic/src/components/TopMenu/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {Link} from 'react-router';
4 |
5 | const liStyle = {
6 | display: 'inline-block',
7 | margin: '10px 20px'
8 | }
9 |
10 | const view = () => {
11 | return (
12 |
13 |
14 | Home
15 | About
16 |
17 |
18 | );
19 | };
20 |
21 | export {view};
22 |
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/src/Provider.js:
--------------------------------------------------------------------------------
1 | import {PropTypes, Component} from 'react';
2 |
3 | class Provider extends Component {
4 |
5 | getChildContext() {
6 | return {
7 | store: this.props.store
8 | };
9 | }
10 |
11 | render() {
12 | return this.props.children;
13 | }
14 |
15 | }
16 |
17 | Provider.propTypes = {
18 | store: PropTypes.object.isRequired
19 | }
20 |
21 | Provider.childContextTypes = {
22 | store: PropTypes.object
23 | };
24 |
25 | export default Provider;
26 |
--------------------------------------------------------------------------------
/chapter-11/react_router_chunked/src/components/TopMenu/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {Link} from 'react-router';
4 |
5 | const liStyle = {
6 | display: 'inline-block',
7 | margin: '10px 20px'
8 | }
9 |
10 | const view = () => {
11 | return (
12 |
13 |
14 | Home
15 | About
16 |
17 |
18 | );
19 | };
20 |
21 | export {view};
22 |
--------------------------------------------------------------------------------
/chapter-12/express_server/server/index.js:
--------------------------------------------------------------------------------
1 | const isProductionMode = (process.env.NODE_ENV === 'production');
2 | const app = isProductionMode ? require('./app.prod.js'): require('./app.dev.js');
3 |
4 | if (!isProductionMode) {
5 | process.env.NODE_ENV = 'development';
6 | }
7 |
8 | const PORT = process.env.PORT || 9000;
9 |
10 | app.listen(PORT, function() {
11 | console.log('running in ' + (isProductionMode ? 'producition' : 'development') + ' mode');
12 | console.log('listening on port: ' + PORT);
13 | });
14 |
--------------------------------------------------------------------------------
/chapter-07/weather_react/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "weather_react",
3 | "version": "0.1.0",
4 | "private": true,
5 | "proxy": "http://www.weather.com.cn/",
6 | "devDependencies": {
7 | "react-scripts": "0.8.4"
8 | },
9 | "dependencies": {
10 | "react": "^15.4.1",
11 | "react-dom": "^15.4.1"
12 | },
13 | "scripts": {
14 | "start": "react-scripts start",
15 | "build": "react-scripts build",
16 | "test": "react-scripts test --env=jsdom",
17 | "eject": "react-scripts eject"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/chapter-12/express_server/server/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%= title %>
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/chapter-09/promise_middleware/src/simple.js:
--------------------------------------------------------------------------------
1 | function isPromise(obj) {
2 | return obj && typeof obj.then === 'function';
3 | }
4 |
5 | /*
6 | export default function promiseMiddleware({dispatch}) {
7 | return next => action => {
8 | return isPromise(action) ? action.then(dispatch) : next(action);
9 | }
10 | }
11 | */
12 |
13 | export default function promiseMiddleware({dispatch}) {
14 | return function(next) {
15 | return function(action) {
16 | return isPromise(action) ? action.then(dispatch) : next(action);
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/filter/views/filters.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from './link.js';
3 | import {FilterTypes} from '../../constants.js'
4 |
5 | import './style.css';
6 |
7 | const Filters = () => {
8 | return (
9 |
10 | {FilterTypes.ALL}
11 | {FilterTypes.COMPLETED}
12 | {FilterTypes.UNCOMPLETED}
13 |
14 | );
15 | };
16 |
17 | export default Filters;
18 |
--------------------------------------------------------------------------------
/chapter-06/function_as_child/test/AddUserProp.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {mount} from 'enzyme';
3 |
4 | import AddUserProp from '../src/AddUserProp.js';
5 |
6 | describe('AddUserProp', () => {
7 | it('should add user', () => {
8 | const wrapper = mount(
9 |
10 | {
11 | (user) => {user}
12 | }
13 |
14 | );
15 |
16 | const userText = wrapper.find('div').text();
17 | expect(userText).toEqual('mock user');
18 |
19 | });
20 |
21 | });
22 |
23 |
24 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/filter/views/filters.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from './link.js';
3 | import {FilterTypes} from '../../constants.js'
4 |
5 | import './style.css';
6 |
7 | const Filters = () => {
8 | return (
9 |
10 | {FilterTypes.ALL}
11 | {FilterTypes.COMPLETED}
12 | {FilterTypes.UNCOMPLETED}
13 |
14 | );
15 | };
16 |
17 | export default Filters;
18 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux/test/weather/reducer.test.js:
--------------------------------------------------------------------------------
1 | import * as actions from '../../src/weather/actions.js';
2 | import * as actionTypes from '../../src/weather/actionTypes.js';
3 | import * as Status from '../../src/weather/status.js';
4 | import reducer from '../../src/weather/reducer.js';
5 |
6 | describe('weather/reducer', () => {
7 | it('should return loading status', () => {
8 | const action = actions.fetchWeatherStarted();
9 |
10 | const newState = reducer({}, action);
11 |
12 | expect(newState.status).toBe(Status.LOADING);
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/filter/views/filters.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from './link.js';
3 | import {FilterTypes} from '../../constants.js'
4 |
5 | import './style.css';
6 |
7 | const Filters = () => {
8 | return (
9 |
10 | {FilterTypes.ALL}
11 | {FilterTypes.COMPLETED}
12 | {FilterTypes.UNCOMPLETED}
13 |
14 | );
15 | };
16 |
17 | export default Filters;
18 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/components/TopMenu/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {Link} from 'react-router';
4 |
5 | const liStyle = {
6 | display: 'inline-block',
7 | margin: '10px 20px'
8 | }
9 |
10 | const view = () => {
11 | return (
12 |
13 |
14 | Home
15 | Counter
16 | About
17 |
18 |
19 | );
20 | };
21 |
22 | export {view};
23 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/filter/views/filters.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from './link.js';
3 | import {FilterTypes} from '../../constants.js'
4 |
5 | import './style.css';
6 |
7 | const Filters = () => {
8 | return (
9 |
10 | {FilterTypes.ALL}
11 | {FilterTypes.COMPLETED}
12 | {FilterTypes.UNCOMPLETED}
13 |
14 | );
15 | };
16 |
17 | export default Filters;
18 |
--------------------------------------------------------------------------------
/chapter-06/hoc/src/proxy/RefsHOC.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const refsHOC = (WrappedComponent) => {
4 | return class HOCComponent extends React.Component {
5 | constructor() {
6 | super(...arguments);
7 |
8 | this.linkRef = this.linkRef.bind(this);
9 | }
10 |
11 | linkRef(wrappedInstance) {
12 | this._root = wrappedInstance;
13 | }
14 |
15 | render() {
16 | const props = {...this.props, ref: this.linkRef};
17 | return ;
18 | }
19 | };
20 | };
21 |
22 | export default refsHOC;
23 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/filter/views/filters.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from './link.js';
3 | import {FilterTypes} from '../../constants.js'
4 |
5 | import './style.css';
6 |
7 | const Filters = () => {
8 | return (
9 |
10 | {FilterTypes.ALL}
11 | {FilterTypes.COMPLETED}
12 | {FilterTypes.UNCOMPLETED}
13 |
14 | );
15 | };
16 |
17 | export default Filters;
18 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/components/TopMenu/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {Link} from 'react-router';
4 |
5 | const liStyle = {
6 | display: 'inline-block',
7 | margin: '10px 20px'
8 | }
9 |
10 | const view = () => {
11 | return (
12 |
13 |
14 | Home
15 | Counter
16 | About
17 |
18 |
19 | );
20 | };
21 |
22 | export {view};
23 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/filter/views/filters.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Link from './link.js';
3 | import {FilterTypes} from '../../constants.js'
4 |
5 | import './style.css';
6 |
7 | const Filters = () => {
8 | return (
9 |
10 | {FilterTypes.ALL}
11 | {FilterTypes.COMPLETED}
12 | {FilterTypes.UNCOMPLETED}
13 |
14 | );
15 | };
16 |
17 | export default Filters;
18 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/components/TopMenu/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | import {Link} from 'react-router';
4 |
5 | const liStyle = {
6 | display: 'inline-block',
7 | margin: '10px 20px'
8 | }
9 |
10 | const view = () => {
11 | return (
12 |
13 |
14 | Home
15 | Counter
16 | About
17 |
18 |
19 | );
20 | };
21 |
22 | export {view};
23 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/server/index.js:
--------------------------------------------------------------------------------
1 | require('babel-register');
2 | require('isomorphic-fetch');
3 |
4 | const isProductionMode = (process.env.NODE_ENV === 'production');
5 | const app = isProductionMode ? require('./app.prod.js'): require('./app.dev.js');
6 |
7 | if (!isProductionMode) {
8 | process.env.NODE_ENV = 'development';
9 | }
10 |
11 | const PORT = process.env.PORT || 9000;
12 |
13 | app.listen(PORT, function() {
14 | console.log('running in ' + (isProductionMode ? 'producition' : 'development') + ' mode');
15 | console.log('listening on port: ' + PORT);
16 | });
17 |
--------------------------------------------------------------------------------
/chapter-03/flux/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Suppress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI
14 | if (!process.env.CI) {
15 | argv.push('--watch');
16 | }
17 |
18 |
19 | jest.run(argv);
20 |
--------------------------------------------------------------------------------
/chapter-03/flux/src/views/ControlPanel.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Counter from './Counter.js';
3 | import Summary from './Summary.js';
4 |
5 | const style = {
6 | margin: '20px'
7 | };
8 |
9 | class ControlPanel extends Component {
10 |
11 | render() {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | );
21 | }
22 | }
23 |
24 | export default ControlPanel;
25 |
26 |
--------------------------------------------------------------------------------
/chapter-03/react-redux/src/views/ControlPanel.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Counter from './Counter.js';
3 | import Summary from './Summary.js';
4 |
5 | const style = {
6 | margin: '20px'
7 | };
8 |
9 | class ControlPanel extends Component {
10 | render() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 | }
21 | }
22 |
23 | export default ControlPanel;
24 |
25 |
--------------------------------------------------------------------------------
/chapter-03/redux_basic/src/views/ControlPanel.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Counter from './Counter.js';
3 | import Summary from './Summary.js';
4 |
5 | const style = {
6 | margin: '20px'
7 | };
8 |
9 | class ControlPanel extends Component {
10 | render() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 | }
21 | }
22 |
23 | export default ControlPanel;
24 |
25 |
--------------------------------------------------------------------------------
/chapter-06/hoc/src/inheritance/ModifyPropsHOC.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const modifyPropsHOC = (WrappedComponent) => {
4 | return class NewComponent extends WrappedComponent {
5 | render() {
6 | const elements = super.render();
7 |
8 | const newStyle = {
9 | color: (elements && elements.type === 'div') ? 'red' : 'green'
10 | }
11 | const newProps = {...this.props, style: newStyle};
12 |
13 | return React.cloneElement(elements, newProps, elements.props.children);
14 | }
15 | };
16 | };
17 |
18 | export default modifyPropsHOC;
19 |
--------------------------------------------------------------------------------
/chapter-03/redux_smart_dumb/src/views/ControlPanel.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Counter from './Counter.js';
3 | import Summary from './Summary.js';
4 |
5 | const style = {
6 | margin: '20px'
7 | };
8 |
9 | class ControlPanel extends Component {
10 | render() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | );
20 | }
21 | }
22 |
23 | export default ControlPanel;
24 |
25 |
--------------------------------------------------------------------------------
/chapter-01/first_react_app/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Suppress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI
14 | if (!process.env.CI) {
15 | argv.push('--watch');
16 | }
17 |
18 |
19 | jest.run(argv);
20 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Suppress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI
14 | if (!process.env.CI) {
15 | argv.push('--watch');
16 | }
17 |
18 |
19 | jest.run(argv);
20 |
--------------------------------------------------------------------------------
/chapter-03/react-redux/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Suppress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI
14 | if (!process.env.CI) {
15 | argv.push('--watch');
16 | }
17 |
18 |
19 | jest.run(argv);
20 |
--------------------------------------------------------------------------------
/chapter-03/redux_basic/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Suppress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI
14 | if (!process.env.CI) {
15 | argv.push('--watch');
16 | }
17 |
18 |
19 | jest.run(argv);
20 |
--------------------------------------------------------------------------------
/chapter-03/redux_smart_dumb/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Suppress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI
14 | if (!process.env.CI) {
15 | argv.push('--watch');
16 | }
17 |
18 |
19 | jest.run(argv);
20 |
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Suppress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI
14 | if (!process.env.CI) {
15 | argv.push('--watch');
16 | }
17 |
18 |
19 | jest.run(argv);
20 |
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/src/views/ControlPanel.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Counter from './Counter.js';
3 | import Summary from './Summary.js';
4 |
5 | const style = {
6 | margin: '20px'
7 | };
8 |
9 | class ControlPanel extends Component {
10 |
11 | render() {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | );
21 | }
22 | }
23 |
24 | export default ControlPanel;
25 |
26 |
--------------------------------------------------------------------------------
/chapter-06/hoc/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "chai": "^3.5.0",
7 | "chai-enzyme": "^0.6.1",
8 | "enzyme": "^2.7.0",
9 | "react-addons-test-utils": "^15.4.1",
10 | "react-redux": "^5.0.1",
11 | "react-scripts": "0.8.4",
12 | "redux": "^3.6.0"
13 | },
14 | "dependencies": {
15 | "react": "^15.4.1",
16 | "react-dom": "^15.4.1",
17 | "react-redux": "^5.0.1",
18 | "redux": "^3.6.0"
19 | },
20 | "scripts": {
21 | "test": "react-scripts test --env=jsdom"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/chapter-11/react_router_basic/src/Store.js:
--------------------------------------------------------------------------------
1 | //import {createStore, compose} from 'redux';
2 | //const reducer = f => f;
3 | import {createStore, combineReducers, compose} from 'redux';
4 | import {routerReducer} from 'react-router-redux';
5 |
6 | const reducer = combineReducers({
7 | routing: routerReducer
8 | });
9 |
10 | const win = window;
11 | const storeEnhancers = compose(
12 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
13 | );
14 |
15 | const initialState = {};
16 | //const initialState = {};
17 | export default createStore(reducer, initialState, storeEnhancers);
18 |
19 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel_with_summary/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Suppress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI
14 | if (!process.env.CI) {
15 | argv.push('--watch');
16 | }
17 |
18 |
19 | jest.run(argv);
20 |
--------------------------------------------------------------------------------
/chapter-06/hoc/test/proxy/RefsHOC.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {mount} from 'enzyme';
3 |
4 | import refsHOC from '../../src/proxy/refsHOC.js';
5 |
6 | describe('refsHOC', () => {
7 | class DemoComponent extends React.Component {
8 | render() {
9 | return do something
;
10 | }
11 | }
12 |
13 | it('should get wrapped component by ref', () => {
14 | const NewComponent = refsHOC(DemoComponent);
15 | const wrapper = mount( );
16 |
17 | expect(wrapper.instance()._root).toBeInstanceOf(DemoComponent);
18 | });
19 | });
20 |
21 |
22 |
--------------------------------------------------------------------------------
/chapter-11/react_router_chunked/src/Store.js:
--------------------------------------------------------------------------------
1 | //import {createStore, compose} from 'redux';
2 | //const reducer = f => f;
3 | import {createStore, combineReducers, compose} from 'redux';
4 | import {routerReducer} from 'react-router-redux';
5 |
6 | const reducer = combineReducers({
7 | routing: routerReducer
8 | });
9 |
10 | const win = window;
11 | const storeEnhancers = compose(
12 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
13 | );
14 |
15 | const initialState = {};
16 | //const initialState = {};
17 | export default createStore(reducer, initialState, storeEnhancers);
18 |
19 |
--------------------------------------------------------------------------------
/chapter-03/react-redux/src/views/Summary.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import {connect} from 'react-redux';
3 |
4 | function Summary({value}) {
5 | return (
6 | Total Count: {value}
7 | );
8 | }
9 |
10 | Summary.PropTypes = {
11 | value: PropTypes.number.isRequired
12 | };
13 |
14 | function mapStateToProps(state) {
15 | let sum = 0;
16 | for (const key in state) {
17 | if (state.hasOwnProperty(key)) {
18 | sum += state[key];
19 | }
20 | }
21 | return {value: sum};
22 | }
23 |
24 |
25 | export default connect(mapStateToProps)(Summary);
26 |
27 |
28 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux/src/weather/reducer.js:
--------------------------------------------------------------------------------
1 | import {FETCH_STARTED, FETCH_SUCCESS, FETCH_FAILURE} from './actionTypes.js';
2 | import * as Status from './status.js';
3 |
4 | export default (state = {status: Status.LOADING}, action) => {
5 | switch(action.type) {
6 | case FETCH_STARTED: {
7 | return {status: Status.LOADING};
8 | }
9 | case FETCH_SUCCESS: {
10 | return {...state, status: Status.SUCCESS, ...action.result};
11 | }
12 | case FETCH_FAILURE: {
13 | return {status: Status.FAILURE};
14 | }
15 | default: {
16 | return state;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/chapter-01/first_react_app/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import logo from './logo.svg';
3 | import './App.css';
4 |
5 | class App extends Component {
6 | render() {
7 | return (
8 |
9 |
10 |
11 |
Welcome to React
12 |
13 |
14 | To get started, edit src/App.js and save to reload.
15 |
16 |
17 | );
18 | }
19 | }
20 |
21 | export default App;
22 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/filter/views/style.css:
--------------------------------------------------------------------------------
1 | .filters {
2 | font-size: 20px;
3 | }
4 |
5 | .filters .filter {
6 | margin: 3px;
7 | padding: 3px 7px;
8 | text-decoration: none;
9 | border: 1px solid transparent;
10 | border-radius: 3px;
11 | }
12 |
13 | .filters .selected {
14 | border: 1px solid transparent;
15 | text-decoration: none;
16 | }
17 |
18 | .filters .not-selected {
19 | color: black;
20 | text-decoration: none;
21 | border: 1px solid;
22 | border-color: rgba(175, 47, 47, 0.2);
23 | }
24 |
25 | .filters .not-selected:hover {
26 | border-color: rgba(175, 47, 47, 0.2);
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/chapter-04/todo/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "react-scripts": "0.8.4",
7 | "redux-immutable-state-invariant": "^1.2.4"
8 | },
9 | "dependencies": {
10 | "react": "^15.4.1",
11 | "react-addons-perf": "^15.4.1",
12 | "react-dom": "^15.4.1",
13 | "react-redux": "^5.0.1",
14 | "redux": "^3.6.0"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test --env=jsdom",
20 | "eject": "react-scripts eject"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/filter/views/style.css:
--------------------------------------------------------------------------------
1 | .filters {
2 | font-size: 20px;
3 | }
4 |
5 | .filters .filter {
6 | margin: 3px;
7 | padding: 3px 7px;
8 | text-decoration: none;
9 | border: 1px solid transparent;
10 | border-radius: 3px;
11 | }
12 |
13 | .filters .selected {
14 | border: 1px solid transparent;
15 | text-decoration: none;
16 | }
17 |
18 | .filters .not-selected {
19 | color: black;
20 | text-decoration: none;
21 | border: 1px solid;
22 | border-color: rgba(175, 47, 47, 0.2);
23 | }
24 |
25 | .filters .not-selected:hover {
26 | border-color: rgba(175, 47, 47, 0.2);
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux_improved/src/weather/reducer.js:
--------------------------------------------------------------------------------
1 | import {FETCH_STARTED, FETCH_SUCCESS, FETCH_FAILURE} from './actionTypes.js';
2 | import * as Status from './status.js';
3 |
4 | export default (state = {status: Status.LOADING}, action) => {
5 | switch(action.type) {
6 | case FETCH_STARTED: {
7 | return {status: Status.LOADING};
8 | }
9 | case FETCH_SUCCESS: {
10 | return {...state, status: Status.SUCCESS, ...action.result};
11 | }
12 | case FETCH_FAILURE: {
13 | return {status: Status.FAILURE};
14 | }
15 | default: {
16 | return state;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/filter/views/style.css:
--------------------------------------------------------------------------------
1 | .filters {
2 | font-size: 20px;
3 | }
4 |
5 | .filters .filter {
6 | margin: 3px;
7 | padding: 3px 7px;
8 | text-decoration: none;
9 | border: 1px solid transparent;
10 | border-radius: 3px;
11 | }
12 |
13 | .filters .selected {
14 | border: 1px solid transparent;
15 | text-decoration: none;
16 | }
17 |
18 | .filters .not-selected {
19 | color: black;
20 | text-decoration: none;
21 | border: 1px solid;
22 | border-color: rgba(175, 47, 47, 0.2);
23 | }
24 |
25 | .filters .not-selected:hover {
26 | border-color: rgba(175, 47, 47, 0.2);
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/chapter-11/react_router_basic/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "multi_pages",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "react-scripts": "0.8.4"
7 | },
8 | "dependencies": {
9 | "react": "^15.4.1",
10 | "react-dom": "^15.4.1",
11 | "react-redux": "^5.0.1",
12 | "react-router": "^3.0.0",
13 | "react-router-redux": "^4.0.7",
14 | "redux": "^3.6.0"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test --env=jsdom",
20 | "eject": "react-scripts eject"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "react-scripts": "0.8.4",
7 | "redux-immutable-state-invariant": "^1.2.4"
8 | },
9 | "dependencies": {
10 | "react": "^15.4.1",
11 | "react-addons-perf": "^15.4.1",
12 | "react-dom": "^15.4.1",
13 | "react-redux": "^5.0.1",
14 | "redux": "^3.6.0"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test --env=jsdom",
20 | "eject": "react-scripts eject"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/filter/views/style.css:
--------------------------------------------------------------------------------
1 | .filters {
2 | font-size: 20px;
3 | }
4 |
5 | .filters .filter {
6 | margin: 3px;
7 | padding: 3px 7px;
8 | text-decoration: none;
9 | border: 1px solid transparent;
10 | border-radius: 3px;
11 | }
12 |
13 | .filters .selected {
14 | border: 1px solid transparent;
15 | text-decoration: none;
16 | }
17 |
18 | .filters .not-selected {
19 | color: black;
20 | text-decoration: none;
21 | border: 1px solid;
22 | border-color: rgba(175, 47, 47, 0.2);
23 | }
24 |
25 | .filters .not-selected:hover {
26 | border-color: rgba(175, 47, 47, 0.2);
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/filter/views/style.css:
--------------------------------------------------------------------------------
1 | .filters {
2 | font-size: 20px;
3 | }
4 |
5 | .filters .filter {
6 | margin: 3px;
7 | padding: 3px 7px;
8 | text-decoration: none;
9 | border: 1px solid transparent;
10 | border-radius: 3px;
11 | }
12 |
13 | .filters .selected {
14 | border: 1px solid transparent;
15 | text-decoration: none;
16 | }
17 |
18 | .filters .not-selected {
19 | color: black;
20 | text-decoration: none;
21 | border: 1px solid;
22 | border-color: rgba(175, 47, 47, 0.2);
23 | }
24 |
25 | .filters .not-selected:hover {
26 | border-color: rgba(175, 47, 47, 0.2);
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/chapter-12/express_server/server/app.prod.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const path = require('path');
3 |
4 | const app = express();
5 |
6 | const assetManifest = require(path.resolve(__dirname, '../build/asset-manifest.json'));
7 |
8 | app.use(express.static(path.resolve(__dirname, '../build')));
9 |
10 | app.get('*', (req, res) => {
11 | return res.render('index', {
12 | title: 'Sample React App',
13 | PUBLIC_URL: '/',
14 | assetManifest: assetManifest
15 | });
16 | });
17 |
18 | app.set('view engine', 'ejs');
19 | app.set('views', path.resolve(__dirname, 'views'));
20 |
21 | module.exports = app;
22 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/filter/views/style.css:
--------------------------------------------------------------------------------
1 | .filters {
2 | font-size: 20px;
3 | }
4 |
5 | .filters .filter {
6 | margin: 3px;
7 | padding: 3px 7px;
8 | text-decoration: none;
9 | border: 1px solid transparent;
10 | border-radius: 3px;
11 | }
12 |
13 | .filters .selected {
14 | border: 1px solid transparent;
15 | text-decoration: none;
16 | }
17 |
18 | .filters .not-selected {
19 | color: black;
20 | text-decoration: none;
21 | border: 1px solid;
22 | border-color: rgba(175, 47, 47, 0.2);
23 | }
24 |
25 | .filters .not-selected:hover {
26 | border-color: rgba(175, 47, 47, 0.2);
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/src/weather/actions.js:
--------------------------------------------------------------------------------
1 | import {FETCH_STARTED, FETCH_SUCCESS, FETCH_FAILURE} from './actionTypes.js';
2 |
3 | export const fetchWeather = (cityCode) => {
4 | const apiUrl = `/data/cityinfo/${cityCode}.html`;
5 |
6 | return {
7 | promise: fetch(apiUrl).then(response => {
8 | if (response.status !== 200) {
9 | throw new Error('Fail to get response with status ' + response.status);
10 | }
11 |
12 | return response.json().then(responseJson => responseJson.weatherinfo);
13 | }),
14 | types: [FETCH_STARTED, FETCH_SUCCESS, FETCH_FAILURE]
15 | };
16 |
17 | }
18 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "react-scripts": "0.8.4",
7 | "redux-immutable-state-invariant": "^1.2.4"
8 | },
9 | "dependencies": {
10 | "react": "^15.4.1",
11 | "react-addons-perf": "^15.4.1",
12 | "react-dom": "^15.4.1",
13 | "react-redux": "^5.0.1",
14 | "redux": "^3.6.0"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test --env=jsdom",
20 | "eject": "react-scripts eject"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/chapter-06/function_as_child/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "chai": "^3.5.0",
7 | "chai-enzyme": "^0.6.1",
8 | "enzyme": "^2.7.0",
9 | "react-addons-test-utils": "^15.4.1",
10 | "react-redux": "^5.0.1",
11 | "react-scripts": "0.8.4",
12 | "redux": "^3.6.0"
13 | },
14 | "dependencies": {
15 | "react": "^15.4.1",
16 | "react-dom": "^15.4.1",
17 | "react-redux": "^5.0.1",
18 | "redux": "^3.6.0",
19 | "sinon": "^1.17.6"
20 | },
21 | "scripts": {
22 | "test": "react-scripts test --env=jsdom"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/src/weather/reducer.js:
--------------------------------------------------------------------------------
1 | import {FETCH_STARTED, FETCH_SUCCESS, FETCH_FAILURE} from './actionTypes.js';
2 | import * as Status from './status.js';
3 |
4 | export default (state = {status: Status.LOADING}, action) => {
5 | switch(action.type) {
6 | case FETCH_STARTED: {
7 | return {status: Status.LOADING};
8 | }
9 | case FETCH_SUCCESS: {
10 | return {...state, status: Status.SUCCESS, ...action.result};
11 | }
12 | case FETCH_FAILURE: {
13 | return {status: Status.FAILURE, error: action.error};
14 | }
15 | default: {
16 | return state;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/server/views/index.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | <%= title %>
8 |
9 |
10 | <%- appHtml %>
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/server/app.prod.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const path = require('path');
3 | const renderPage = require('./routes.Server.js').renderPage;
4 |
5 | const app = express();
6 |
7 | const assetManifest = require(path.resolve(__dirname, '../build/asset-manifest.json'));
8 |
9 | app.use(express.static(path.resolve(__dirname, '../build')));
10 |
11 | app.use('/api/count', (req, res) => {
12 | res.json({count: 100});
13 | });
14 |
15 | app.get('*', (req, res) => {
16 | return renderPage(req, res, assetManifest);
17 | });
18 |
19 | app.set('view engine', 'ejs');
20 | app.set('views', path.resolve(__dirname, 'views'));
21 |
22 | module.exports = app;
23 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel/src/ControlPanel.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Counter from './Counter.js';
3 |
4 | const style = {
5 | margin: '20px'
6 | };
7 |
8 | class ControlPanel extends Component {
9 | render() {
10 | console.log('enter ControlPanel render');
11 | return (
12 |
13 |
14 |
15 |
16 | this.forceUpdate() }>
17 | Click me to re-render!
18 |
19 |
20 | );
21 | }
22 | }
23 |
24 | export default ControlPanel;
25 |
26 |
--------------------------------------------------------------------------------
/chapter-03/flux/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/chapter-09/promise_middleware/src/advanced.js:
--------------------------------------------------------------------------------
1 | function isPromise(obj) {
2 | return obj && typeof obj.then === 'function';
3 | }
4 |
5 | export default function promiseMiddleware({dispatch}) {
6 | return (next) => (action) => {
7 | const {types, promise, ...rest} = action;
8 | if (!isPromise(promise) || !(action.types && action.types.length === 3)) {
9 | return next(action);
10 | }
11 |
12 | const [PENDING, DONE, FAIL] = types;
13 |
14 | dispatch({...rest, type: PENDING});
15 | return action.promise.then(
16 | (result) => dispatch({...rest, result, type: DONE}),
17 | (error) => dispatch({...rest, error, type: FAIL})
18 | );
19 | };
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/chapter-03/react-redux/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/chapter-03/redux_basic/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/chapter-01/first_react_app/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/chapter-03/redux_smart_dumb/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/chapter-03/redux_with_context/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/chapter-12/express_server/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/chapter-11/react_router_chunked/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel_with_summary/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/chapter-06/function_as_child/test/countDown.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {mount} from 'enzyme';
3 | import {spy} from 'sinon';
4 |
5 | import CountDown from '../src/CountDown.js';
6 |
7 | describe('CountDown', () => {
8 | it('should count down', (done) => {
9 | const counter = spy();
10 | const wrapper = mount(
11 |
12 | {
13 | (count) => {
14 | counter();
15 | if (count === 0) {
16 | expect(counter.callCount).toEqual(3);
17 | done();
18 | }
19 | return null;
20 | }
21 | }
22 |
23 | );
24 | });
25 |
26 | });
27 |
28 |
29 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "react-scripts": "0.8.4",
7 | "redux-immutable-state-invariant": "^1.2.4"
8 | },
9 | "dependencies": {
10 | "react": "^15.4.1",
11 | "react-addons-css-transition-group": "^15.4.1",
12 | "react-addons-perf": "^15.4.1",
13 | "react-dom": "^15.4.1",
14 | "react-redux": "^5.0.1",
15 | "redux": "^3.6.0",
16 | "reselect": "^2.5.4"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "test": "react-scripts test --env=jsdom",
22 | "eject": "react-scripts eject"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux_improved/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "weather",
3 | "version": "0.1.0",
4 | "private": true,
5 | "proxy": "http://www.weather.com.cn/",
6 | "devDependencies": {
7 | "react-scripts": "0.8.4",
8 | "redux-immutable-state-invariant": "^1.2.4"
9 | },
10 | "dependencies": {
11 | "react": "^15.4.1",
12 | "react-addons-perf": "^15.4.1",
13 | "react-dom": "^15.4.1",
14 | "react-redux": "^5.0.1",
15 | "redux": "^3.6.0",
16 | "redux-thunk": "^2.1.0"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "test": "react-scripts test --env=jsdom",
22 | "eject": "react-scripts eject"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/chapter-10/animation_types/setInterval_animation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/todos/selector.js:
--------------------------------------------------------------------------------
1 | import {createSelector} from 'reselect';
2 | import {FilterTypes} from '../constants.js';
3 |
4 | const getFilter = (state) => state.filter;
5 | const getTodos = (state) => state.todos;
6 |
7 | export const selectVisibleTodos = createSelector(
8 | [getFilter, getTodos],
9 | (filter, todos) => {
10 | switch (filter) {
11 | case FilterTypes.ALL:
12 | return todos;
13 | case FilterTypes.COMPLETED:
14 | return todos.filter(item => item.completed);
15 | case FilterTypes.UNCOMPLETED:
16 | return todos.filter(item => !item.completed);
17 | default:
18 | throw new Error('unsupported filter');
19 | }
20 | }
21 | );
22 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/todos/selector.js:
--------------------------------------------------------------------------------
1 | import {createSelector} from 'reselect';
2 | import {FilterTypes} from '../constants.js';
3 |
4 | const getFilter = (state) => state.filter;
5 | const getTodos = (state) => state.todos;
6 |
7 | export const selectVisibleTodos = createSelector(
8 | [getFilter, getTodos],
9 | (filter, todos) => {
10 | switch (filter) {
11 | case FilterTypes.ALL:
12 | return todos;
13 | case FilterTypes.COMPLETED:
14 | return todos.filter(item => item.completed);
15 | case FilterTypes.UNCOMPLETED:
16 | return todos.filter(item => !item.completed);
17 | default:
18 | throw new Error('unsupported filter');
19 | }
20 | }
21 | );
22 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/todos/selector.js:
--------------------------------------------------------------------------------
1 | import {createSelector} from 'reselect';
2 | import {FilterTypes} from '../constants.js';
3 |
4 | const getFilter = (state) => state.filter;
5 | const getTodos = (state) => state.todos;
6 |
7 | export const selectVisibleTodos = createSelector(
8 | [getFilter, getTodos],
9 | (filter, todos) => {
10 | switch (filter) {
11 | case FilterTypes.ALL:
12 | return todos;
13 | case FilterTypes.COMPLETED:
14 | return todos.filter(item => item.completed);
15 | case FilterTypes.UNCOMPLETED:
16 | return todos.filter(item => !item.completed);
17 | default:
18 | throw new Error('unsupported filter');
19 | }
20 | }
21 | );
22 |
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "weather",
3 | "version": "0.1.0",
4 | "private": true,
5 | "proxy": "http://www.weather.com.cn/",
6 | "devDependencies": {
7 | "react-scripts": "0.8.4",
8 | "redux-immutable-state-invariant": "^1.2.4"
9 | },
10 | "dependencies": {
11 | "react": "^15.4.1",
12 | "react-addons-perf": "^15.4.1",
13 | "react-dom": "^15.4.1",
14 | "react-redux": "^5.0.1",
15 | "redux": "^3.6.0",
16 | "redux-thunk": "^2.1.0"
17 | },
18 | "scripts": {
19 | "start": "react-scripts start",
20 | "build": "react-scripts build",
21 | "test": "react-scripts test --env=jsdom",
22 | "eject": "react-scripts eject"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/src/middleware/promise_middleware.js:
--------------------------------------------------------------------------------
1 | function isPromise(obj) {
2 | return obj && typeof obj.then === 'function';
3 | }
4 |
5 | export default function promiseMiddleware({dispatch}) {
6 | return (next) => (action) => {
7 | const {types, promise, ...rest} = action;
8 | if (!isPromise(promise) || !(action.types && action.types.length === 3)) {
9 | return next(action);
10 | }
11 |
12 | const [PENDING, DONE, FAIL] = types;
13 |
14 | dispatch({...rest, type: PENDING});
15 | return action.promise.then(
16 | (result) => dispatch({...rest, result, type: DONE}),
17 | (error) => dispatch({...rest, error, type: FAIL})
18 | );
19 | };
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/chapter-06/hoc/test/proxy/removeUserPropHOC.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {mount, shallow} from 'enzyme';
3 |
4 | import removeUserPropHOC from '../../src/proxy/removeUserPropHOC.js';
5 |
6 | describe('removeUserPropHOC', () => {
7 |
8 | const DemoComponent = (props) => {
9 | return (
10 | render something.
11 | );
12 | };
13 |
14 | it('should pass new props to wrapped component', () => {
15 | const NewComponent = removeUserPropHOC(DemoComponent);
16 | const wrapper = mount( );
17 | const expectedComponent =
18 |
19 | expect(wrapper.contains(expectedComponent)).toEqual(true);
20 | });
21 |
22 | });
23 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "enzyme": "^2.7.0",
7 | "react-addons-test-utils": "^15.4.2",
8 | "react-scripts": "0.8.4",
9 | "redux-immutable-state-invariant": "^1.2.4"
10 | },
11 | "dependencies": {
12 | "react": "^15.4.1",
13 | "react-addons-perf": "^15.4.1",
14 | "react-dom": "^15.4.1",
15 | "react-redux": "^5.0.1",
16 | "redux": "^3.6.0",
17 | "reselect": "^2.5.4"
18 | },
19 | "scripts": {
20 | "start": "react-scripts start",
21 | "build": "react-scripts build",
22 | "test": "react-scripts test --env=jsdom",
23 | "eject": "react-scripts eject"
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/pages/CounterPage.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {view as Counter, stateKey, reducer} from '../components/Counter';
3 |
4 | const page = () => {
5 | return (
6 |
10 | );
11 | };
12 |
13 | const END_POINT = process.env.HOST_NAME || 'localhost:9000';
14 |
15 | const initState = () => {
16 | return fetch(`http://${END_POINT}/api/count`).then(response => {
17 | if (response.status !== 200) {
18 | throw new Error('Fail to fetch count');
19 | }
20 | return response.json();
21 | }).then(responseJson => {
22 | return responseJson.count;
23 | });
24 | }
25 |
26 | export {page, reducer, initState, stateKey};
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-and-redux
2 |
3 | 《深入浅出React和Redux》已近由机械工业出版社发行,这个repo存放的是书中所有的代码。
4 |
5 | 配合React和Redux的持续讨论,作者开通了一个知乎专栏[《进击的React》](https://zhuanlan.zhihu.com/advancing-react),欢迎关注。对React和Redux技术有问题可以[通过私信或者值乎咨询](https://www.zhihu.com/zhi/people/828707098316656640),有问必答。
6 |
7 | [京东](http://item.jd.com/12073933.html)(这个链接里有书的目录)
8 |
9 | [亚马逊](https://www.amazon.cn/%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BAReact%E5%92%8CRedux-%E7%A8%8B%E5%A2%A8/dp/B072BM636Z/ref=sr_1_1?ie=UTF8&qid=1494646329&sr=8-1&keywords=%E6%B7%B1%E5%85%A5%E6%B5%85%E5%87%BAreact%E5%92%8Credux)
10 |
11 | [当当网](http://product.dangdang.com/25072226.html)
12 |
13 | 
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "todo",
3 | "version": "0.1.0",
4 | "private": true,
5 | "devDependencies": {
6 | "enzyme": "^2.7.0",
7 | "react-addons-test-utils": "^15.4.2",
8 | "react-scripts": "0.8.4",
9 | "redux-immutable-state-invariant": "^1.2.4"
10 | },
11 | "dependencies": {
12 | "react": "^15.4.1",
13 | "react-addons-perf": "^15.4.1",
14 | "react-dom": "^15.4.1",
15 | "react-motion": "^0.4.7",
16 | "react-redux": "^5.0.1",
17 | "redux": "^3.6.0",
18 | "reselect": "^2.5.4"
19 | },
20 | "scripts": {
21 | "start": "react-scripts start",
22 | "build": "react-scripts build",
23 | "test": "react-scripts test --env=jsdom",
24 | "eject": "react-scripts eject"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 |
6 | # Runtime data
7 | pids
8 | *.pid
9 | *.seed
10 |
11 | # Directory for instrumented libs generated by jscoverage/JSCover
12 | lib-cov
13 |
14 | # Coverage directory used by tools like istanbul
15 | coverage
16 |
17 | # nyc test coverage
18 | .nyc_output
19 |
20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
21 | .grunt
22 |
23 | # node-waf configuration
24 | .lock-wscript
25 |
26 | # Compiled binary addons (http://nodejs.org/api/addons.html)
27 | build/Release
28 | build
29 |
30 | # Dependency directories
31 | node_modules
32 | jspm_packages
33 |
34 | # Optional npm cache directory
35 | .npm
36 |
37 | # Optional REPL history
38 | .node_repl_history
39 |
40 | .DS_Store
41 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "weather",
3 | "version": "0.1.0",
4 | "private": true,
5 | "proxy": "http://www.weather.com.cn/",
6 | "devDependencies": {
7 | "react-scripts": "0.8.4",
8 | "redux-immutable-state-invariant": "^1.2.4",
9 | "redux-mock-store": "^1.2.1",
10 | "sinon": "^1.17.7"
11 | },
12 | "dependencies": {
13 | "react": "^15.4.1",
14 | "react-addons-perf": "^15.4.1",
15 | "react-dom": "^15.4.1",
16 | "react-redux": "^5.0.1",
17 | "redux": "^3.6.0",
18 | "redux-thunk": "^2.1.0"
19 | },
20 | "scripts": {
21 | "start": "react-scripts start",
22 | "build": "react-scripts build",
23 | "test": "react-scripts test --env=jsdom",
24 | "eject": "react-scripts eject"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/test/filter/views/filters.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {shallow} from 'enzyme';
3 | import Filters from '../../../src/filter/views/filters.js';
4 | import Link from '../../../src/filter/views/link.js';
5 | import {FilterTypes} from '../../../src/constants.js';
6 |
7 | describe('filters', () => {
8 | it('should render three link', () => {
9 | const wrapper = shallow( );
10 |
11 | expect(wrapper.contains( {FilterTypes.ALL} )).toBe(true);
12 | expect(wrapper.contains( {FilterTypes.COMPLETED} )).toBe(true);
13 | expect(wrapper.contains( {FilterTypes.UNCOMPLETED} )).toBe(true);
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/chapter-06/hoc/src/inheritance/removeUserPropHOC.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | function removeUserProp(WrappedComponent) {
4 | return class NewComponent extends WrappedComponent {
5 | render() {
6 | const {user, ...otherProps} = this.props;
7 | this.props = otherProps;
8 | return super.render();
9 | }
10 | };
11 | }
12 |
13 | /*
14 | function removeUserProp(WrappedComponent) {
15 | return class NewComponent extends WrappedComponent {
16 | render() {
17 | const elements = super.render();
18 | const {user, ...otherProps} = this.props;
19 |
20 | console.log('##', elements);
21 |
22 | return React.cloneElement(elements, otherProps, elements.props.children);
23 | }
24 | };
25 | }
26 | */
27 |
28 | export default removeUserProp;
29 |
--------------------------------------------------------------------------------
/chapter-06/hoc/test/inheritance/removeUserPropHOC.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {mount, shallow} from 'enzyme';
3 |
4 | import removeUserPropHOC from '../../src/inheritance/removeUserPropHOC.js';
5 |
6 | describe('removeUserPropHOC', () => {
7 |
8 | class DemoComponent extends React.Component {
9 | render() {
10 | return (
11 | {this.props.user || 'no_user'}
12 | );
13 | }
14 | }
15 |
16 | it('should pass new props to wrapped component', () => {
17 | const NewComponent = removeUserPropHOC(DemoComponent);
18 | const wrapper = mount( );
19 | const expectedComponent = no_user
;
20 |
21 | expect(wrapper.contains(expectedComponent)).toEqual(true);
22 | });
23 |
24 | });
25 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
2 |
3 | import {reducer as todoReducer} from './todos';
4 | import {reducer as filterReducer} from './filter';
5 |
6 | import Perf from 'react-addons-perf'
7 |
8 | const win = window;
9 | win.Perf = Perf
10 |
11 | const reducer = combineReducers({
12 | todos: todoReducer,
13 | filter: filterReducer
14 | });
15 |
16 | const middlewares = [];
17 | if (process.env.NODE_ENV !== 'production') {
18 | middlewares.push(require('redux-immutable-state-invariant')());
19 | }
20 |
21 | const storeEnhancers = compose(
22 | applyMiddleware(...middlewares),
23 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
24 | );
25 |
26 | export default createStore(reducer, {}, storeEnhancers);
27 |
--------------------------------------------------------------------------------
/chapter-09/reset_enhancer/src/reset.js:
--------------------------------------------------------------------------------
1 | const RESET_ACTION_TYPE = '@@RESET';
2 |
3 | const resetReducerCreator = (reducer, resetState) => (state, action) => {
4 | if (action.type === RESET_ACTION_TYPE) {
5 | return resetState;
6 | } else {
7 | return reducer(state, action);
8 | }
9 | };
10 |
11 | const reset = (createStore) => (reducer, preloadedState, enhancer) => {
12 | const store = createStore(reducer, preloadedState, enhancer);
13 |
14 | const reset = (resetReducer, resetState) => {
15 | const newReducer = resetReducerCreator(resetReducer, resetState);
16 | store.replaceReducer(newReducer);
17 | store.dispatch({type: RESET_ACTION_TYPE, state: resetState});
18 | };
19 |
20 | return {
21 | ...store,
22 | reset
23 | };
24 | };
25 |
26 | export default reset;
27 |
28 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
2 |
3 | import thunkMiddleware from 'redux-thunk'
4 |
5 | import {reducer as weatherReducer} from './weather/';
6 |
7 | import Perf from 'react-addons-perf'
8 |
9 | const win = window;
10 | win.Perf = Perf
11 |
12 | const reducer = combineReducers({
13 | weather: weatherReducer
14 | });
15 |
16 | const middlewares = [thunkMiddleware];
17 | if (process.env.NODE_ENV !== 'production') {
18 | middlewares.push(require('redux-immutable-state-invariant')());
19 | }
20 |
21 | const storeEnhancers = compose(
22 | applyMiddleware(...middlewares),
23 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
24 | );
25 |
26 | export default createStore(reducer, {}, storeEnhancers);
27 |
28 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/enhancer/reset.js:
--------------------------------------------------------------------------------
1 | const RESET_ACTION_TYPE = '@@RESET';
2 |
3 | const resetReducerCreator = (reducer, resetState) => (state, action) => {
4 | if (action.type === RESET_ACTION_TYPE) {
5 | return resetState;
6 | } else {
7 | return reducer(state, action);
8 | }
9 | };
10 |
11 | const reset = (createStore) => (reducer, preloadedState, enhancer) => {
12 | const store = createStore(reducer, preloadedState, enhancer);
13 |
14 | const reset = (resetReducer, resetState) => {
15 | const newReducer = resetReducerCreator(resetReducer, resetState);
16 | store.replaceReducer(newReducer);
17 | store.dispatch({type: RESET_ACTION_TYPE, state: resetState});
18 | };
19 |
20 | return {
21 | ...store,
22 | reset
23 | };
24 | };
25 |
26 | export default reset;
27 |
28 |
--------------------------------------------------------------------------------
/chapter-01/first_react_app/src/ClickCounter.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | class ClickCounter extends Component {
4 |
5 | constructor(props) {
6 | super(props);
7 | this.onClickButton = this.onClickButton.bind(this);
8 | this.state = {
9 | count: 0
10 | }
11 | }
12 |
13 | onClickButton() {
14 | this.setState({count: this.state.count + 1});
15 | }
16 |
17 | render() {
18 | const counterStyle = {
19 | margin: '16px'
20 | }
21 | return (
22 |
23 |
Click Me
24 |
25 | Click Count: {this.state.count}
26 |
27 |
28 | );
29 | }
30 | }
31 |
32 | export default ClickCounter;
33 |
34 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/enhancer/reset.js:
--------------------------------------------------------------------------------
1 | const RESET_ACTION_TYPE = '@@RESET';
2 |
3 | const resetReducerCreator = (reducer, resetState) => (state, action) => {
4 | if (action.type === RESET_ACTION_TYPE) {
5 | return resetState;
6 | } else {
7 | return reducer(state, action);
8 | }
9 | };
10 |
11 | const reset = (createStore) => (reducer, preloadedState, enhancer) => {
12 | const store = createStore(reducer, preloadedState, enhancer);
13 |
14 | const reset = (resetReducer, resetState) => {
15 | const newReducer = resetReducerCreator(resetReducer, resetState);
16 | store.replaceReducer(newReducer);
17 | store.dispatch({type: RESET_ACTION_TYPE, state: resetState});
18 | };
19 |
20 | return {
21 | ...store,
22 | reset
23 | };
24 | };
25 |
26 | export default reset;
27 |
28 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux_improved/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
2 |
3 | import thunkMiddleware from 'redux-thunk'
4 |
5 | import {reducer as weatherReducer} from './weather/';
6 |
7 | import Perf from 'react-addons-perf'
8 |
9 | const win = window;
10 | win.Perf = Perf
11 |
12 | const reducer = combineReducers({
13 | weather: weatherReducer
14 | });
15 |
16 | const middlewares = [thunkMiddleware];
17 | if (process.env.NODE_ENV !== 'production') {
18 | middlewares.push(require('redux-immutable-state-invariant')());
19 | }
20 |
21 | const storeEnhancers = compose(
22 | applyMiddleware(...middlewares),
23 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
24 | );
25 |
26 | export default createStore(reducer, {}, storeEnhancers);
27 |
28 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/enhancer/reset.js:
--------------------------------------------------------------------------------
1 | const RESET_ACTION_TYPE = '@@RESET';
2 |
3 | const resetReducerCreator = (reducer, resetState) => (state, action) => {
4 | if (action.type === RESET_ACTION_TYPE) {
5 | return resetState;
6 | } else {
7 | return reducer(state, action);
8 | }
9 | };
10 |
11 | const reset = (createStore) => (reducer, preloadedState, enhancer) => {
12 | const store = createStore(reducer, preloadedState, enhancer);
13 |
14 | const reset = (resetReducer, resetState) => {
15 | const newReducer = resetReducerCreator(resetReducer, resetState);
16 | store.replaceReducer(newReducer);
17 | store.dispatch({type: RESET_ACTION_TYPE, state: resetState});
18 | };
19 |
20 | return {
21 | ...store,
22 | reset
23 | };
24 | };
25 |
26 | export default reset;
27 |
28 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
2 |
3 | import {reducer as todoReducer} from './todos';
4 | import {reducer as filterReducer} from './filter';
5 |
6 | import Perf from 'react-addons-perf'
7 |
8 | const win = window;
9 | win.Perf = Perf
10 |
11 | const reducer = combineReducers({
12 | todos: todoReducer,
13 | filter: filterReducer
14 | });
15 |
16 | const middlewares = [];
17 | if (process.env.NODE_ENV !== 'production') {
18 | middlewares.push(require('redux-immutable-state-invariant')());
19 | }
20 |
21 | const storeEnhancers = compose(
22 | applyMiddleware(...middlewares),
23 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
24 | );
25 |
26 | export default createStore(reducer, {}, storeEnhancers);
27 |
--------------------------------------------------------------------------------
/chapter-03/flux/src/views/Summary.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | import SummaryStore from '../stores/SummaryStore.js';
4 |
5 | class Summary extends Component {
6 |
7 | constructor(props) {
8 | super(props);
9 |
10 | this.onUpdate = this.onUpdate.bind(this);
11 |
12 | this.state = {
13 | sum: SummaryStore.getSummary()
14 | }
15 | }
16 |
17 | componentDidMount() {
18 | SummaryStore.addChangeListener(this.onUpdate);
19 | }
20 |
21 | componentWillUnmount() {
22 | SummaryStore.removeChangeListener(this.onUpdate);
23 | }
24 |
25 | onUpdate() {
26 | this.setState({
27 | sum: SummaryStore.getSummary()
28 | })
29 | }
30 |
31 | render() {
32 | return (
33 | Total Count: {this.state.sum}
34 | );
35 | }
36 | }
37 |
38 | export default Summary;
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/todos/views/todoList.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react';
2 | import {connect} from 'react-redux';
3 | import TodoItem from './todoItem.js';
4 | import {selectVisibleTodos} from '../selector.js';
5 |
6 | const TodoList = ({todos, onClickTodo}) => {
7 | return (
8 |
9 | {
10 | todos.map((item) => (
11 |
17 | ))
18 | }
19 |
20 | );
21 | };
22 |
23 | TodoList.propTypes = {
24 | todos: PropTypes.array.isRequired
25 | };
26 |
27 | const mapStateToProps = (state) => {
28 | return {
29 | todos: selectVisibleTodos(state)
30 | };
31 | }
32 |
33 | export default connect(mapStateToProps)(TodoList);
34 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/todos/views/todoItem.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react';
2 |
3 | const TodoItem = ({onToggle, onRemove, completed, text}) => {
4 | const checkedProp = completed ? {checked: true} : {};
5 | return (
6 |
12 |
13 | {text}
14 | ×
15 |
16 | )
17 | }
18 |
19 |
20 | TodoItem.propTypes = {
21 | onToggle: PropTypes.func.isRequired,
22 | onRemove: PropTypes.func.isRequired,
23 | completed: PropTypes.bool.isRequired,
24 | text: PropTypes.string.isRequired
25 | }
26 |
27 | export default TodoItem;
28 |
--------------------------------------------------------------------------------
/chapter-06/hoc/test/proxy/StyleHOC.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {mount} from 'enzyme';
3 |
4 | import chai from 'chai';
5 | import chaiEnzyme from 'chai-enzyme';
6 | chai.use(chaiEnzyme());
7 |
8 | const {expect} = chai;
9 |
10 |
11 | import styleHOC from '../../src/proxy/styleHOC.js';
12 |
13 | describe('styleHOC', () => {
14 |
15 | class DemoComponent extends React.Component {
16 | render() {
17 | return do something ;
18 | }
19 | }
20 |
21 | it('should get right style', () => {
22 | const NewComponent = styleHOC(DemoComponent, {color: 'red'});
23 |
24 | const wrapper = mount( );
25 |
26 | expect(wrapper.find('div')).to.have.style('color').equal('red');
27 | expect(wrapper.find('span')).to.have.style('color').equal('green');
28 | });
29 | });
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/todos/reducer.js:
--------------------------------------------------------------------------------
1 | import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO}from './actionTypes.js';
2 |
3 | export default (state = [], action) => {
4 | switch(action.type) {
5 | case ADD_TODO: {
6 | return [
7 | {
8 | id: action.id,
9 | text: action.text,
10 | completed: false
11 | },
12 | ...state
13 | ]
14 | }
15 | case TOGGLE_TODO: {
16 | return state.map((todoItem) => {
17 | if (todoItem.id === action.id) {
18 | return {...todoItem, completed: !todoItem.completed};
19 | } else {
20 | return todoItem;
21 | }
22 | })
23 | }
24 | case REMOVE_TODO: {
25 | return state.filter((todoItem) => {
26 | return todoItem.id !== action.id;
27 | })
28 | }
29 | default: {
30 | return state;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/todos/reducer.js:
--------------------------------------------------------------------------------
1 | import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO}from './actionTypes.js';
2 |
3 | export default (state = [], action) => {
4 | switch(action.type) {
5 | case ADD_TODO: {
6 | return [
7 | {
8 | id: action.id,
9 | text: action.text,
10 | completed: false
11 | },
12 | ...state
13 | ]
14 | }
15 | case TOGGLE_TODO: {
16 | return state.map((todoItem) => {
17 | if (todoItem.id === action.id) {
18 | return {...todoItem, completed: !todoItem.completed};
19 | } else {
20 | return todoItem;
21 | }
22 | })
23 | }
24 | case REMOVE_TODO: {
25 | return state.filter((todoItem) => {
26 | return todoItem.id !== action.id;
27 | })
28 | }
29 | default: {
30 | return state;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/test/todos/actions.test.js:
--------------------------------------------------------------------------------
1 | import * as actions from '../../src/todos/actions.js';
2 | import * as actionTypes from '../../src/todos/actionTypes.js';
3 |
4 | describe('todos/actions', () => {
5 | describe('addTodo', () => {
6 | const addTodo = actions.addTodo
7 |
8 | it('should create an action to add todo', () => {
9 | const text = 'first todo';
10 | const action = addTodo(text);
11 |
12 | expect(action.text).toBe(text);
13 | expect(action.completed).toBe(false);
14 | expect(action.type).toBe(actionTypes.ADD_TODO);
15 | });
16 |
17 | it('should have different id for different actions', () => {
18 | const text = 'first todo';
19 | const action1 = addTodo(text);
20 | const action2 = addTodo(text);
21 |
22 | expect(action1.id !== action2.id).toBe(true);
23 | });
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/todos/reducer.js:
--------------------------------------------------------------------------------
1 | import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO}from './actionTypes.js';
2 |
3 | export default (state = [], action) => {
4 | switch(action.type) {
5 | case ADD_TODO: {
6 | return [
7 | {
8 | id: action.id,
9 | text: action.text,
10 | completed: false
11 | },
12 | ...state
13 | ]
14 | }
15 | case TOGGLE_TODO: {
16 | return state.map((todoItem) => {
17 | if (todoItem.id === action.id) {
18 | return {...todoItem, completed: !todoItem.completed};
19 | } else {
20 | return todoItem;
21 | }
22 | })
23 | }
24 | case REMOVE_TODO: {
25 | return state.filter((todoItem) => {
26 | return todoItem.id !== action.id;
27 | })
28 | }
29 | default: {
30 | return state;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/todos/views/todoItem.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react';
2 |
3 | const TodoItem = ({onToggle, onRemove, completed, text }) => {
4 | const checkedProp = completed ? {checked: true} : {};
5 | return (
6 |
12 |
13 | {text}
14 | ×
15 |
16 | );
17 | }
18 |
19 |
20 | TodoItem.propTypes = {
21 | onToggle: PropTypes.func.isRequired,
22 | onRemove: PropTypes.func.isRequired,
23 | completed: PropTypes.bool.isRequired,
24 | text: PropTypes.string.isRequired
25 | }
26 |
27 | export default TodoItem;
28 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/todos/reducer.js:
--------------------------------------------------------------------------------
1 | import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO}from './actionTypes.js';
2 |
3 | export default (state = [], action) => {
4 | switch(action.type) {
5 | case ADD_TODO: {
6 | return [
7 | {
8 | id: action.id,
9 | text: action.text,
10 | completed: false
11 | },
12 | ...state
13 | ]
14 | }
15 | case TOGGLE_TODO: {
16 | return state.map((todoItem) => {
17 | if (todoItem.id === action.id) {
18 | return {...todoItem, completed: !todoItem.completed};
19 | } else {
20 | return todoItem;
21 | }
22 | })
23 | }
24 | case REMOVE_TODO: {
25 | return state.filter((todoItem) => {
26 | return todoItem.id !== action.id;
27 | })
28 | }
29 | default: {
30 | return state;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/todos/reducer.js:
--------------------------------------------------------------------------------
1 | import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO}from './actionTypes.js';
2 |
3 | export default (state = [], action) => {
4 | switch(action.type) {
5 | case ADD_TODO: {
6 | return [
7 | {
8 | id: action.id,
9 | text: action.text,
10 | completed: false
11 | },
12 | ...state
13 | ]
14 | }
15 | case TOGGLE_TODO: {
16 | return state.map((todoItem) => {
17 | if (todoItem.id === action.id) {
18 | return {...todoItem, completed: !todoItem.completed};
19 | } else {
20 | return todoItem;
21 | }
22 | })
23 | }
24 | case REMOVE_TODO: {
25 | return state.filter((todoItem) => {
26 | return todoItem.id !== action.id;
27 | })
28 | }
29 | default: {
30 | return state;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/todos/reducer.js:
--------------------------------------------------------------------------------
1 | import {ADD_TODO, TOGGLE_TODO, REMOVE_TODO}from './actionTypes.js';
2 |
3 | export default (state = [], action) => {
4 | switch(action.type) {
5 | case ADD_TODO: {
6 | return [
7 | {
8 | id: action.id,
9 | text: action.text,
10 | completed: false
11 | },
12 | ...state
13 | ]
14 | }
15 | case TOGGLE_TODO: {
16 | return state.map((todoItem) => {
17 | if (todoItem.id === action.id) {
18 | return {...todoItem, completed: !todoItem.completed};
19 | } else {
20 | return todoItem;
21 | }
22 | })
23 | }
24 | case REMOVE_TODO: {
25 | return state.filter((todoItem) => {
26 | return todoItem.id !== action.id;
27 | })
28 | }
29 | default: {
30 | return state;
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/chapter-09/weather_with_promise_middleware/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
2 |
3 | //import thunkMiddleware from 'redux-thunk'
4 | import promiseMiddleware from './middleware/promise_middleware.js';
5 |
6 | import {reducer as weatherReducer} from './weather/';
7 |
8 | import Perf from 'react-addons-perf'
9 |
10 | const win = window;
11 | win.Perf = Perf
12 |
13 | const reducer = combineReducers({
14 | weather: weatherReducer
15 | });
16 |
17 | const middlewares = [promiseMiddleware];
18 | if (process.env.NODE_ENV !== 'production') {
19 | middlewares.push(require('redux-immutable-state-invariant')());
20 | }
21 |
22 | const storeEnhancers = compose(
23 | applyMiddleware(...middlewares),
24 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
25 | );
26 |
27 | export default createStore(reducer, {}, storeEnhancers);
28 |
29 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/Store.js:
--------------------------------------------------------------------------------
1 | //import {createStore, compose} from 'redux';
2 | //const reducer = f => f;
3 | import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
4 | import {routerReducer} from 'react-router-redux';
5 |
6 | import resetEnhancer from './enhancer/reset.js';
7 |
8 | const originalReducers = {
9 | routing: routerReducer
10 | }
11 | const reducer = combineReducers(originalReducers);
12 |
13 | const win = window;
14 |
15 | const middlewares = [];
16 | if (process.env.NODE_ENV !== 'production') {
17 | middlewares.push(require('redux-immutable-state-invariant')());
18 | }
19 |
20 | const storeEnhancers = compose(
21 | resetEnhancer,
22 | applyMiddleware(...middlewares),
23 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
24 | );
25 |
26 | const initialState = {
27 | };
28 | const store = createStore(reducer, initialState, storeEnhancers);
29 | store._reducers = originalReducers;
30 | export default store;
31 |
32 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/Store.js:
--------------------------------------------------------------------------------
1 | //import {createStore, compose} from 'redux';
2 | //const reducer = f => f;
3 | import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
4 | import {routerReducer} from 'react-router-redux';
5 |
6 | import resetEnhancer from './enhancer/reset.js';
7 |
8 | const originalReducers = {
9 | routing: routerReducer
10 | }
11 | const reducer = combineReducers(originalReducers);
12 |
13 | const win = window;
14 |
15 | const middlewares = [];
16 | if (process.env.NODE_ENV !== 'production') {
17 | middlewares.push(require('redux-immutable-state-invariant')());
18 | }
19 |
20 | const storeEnhancers = compose(
21 | resetEnhancer,
22 | applyMiddleware(...middlewares),
23 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
24 | );
25 |
26 | const initialState = {
27 | };
28 | const store = createStore(reducer, initialState, storeEnhancers);
29 | store._reducers = originalReducers;
30 | export default store;
31 |
32 |
--------------------------------------------------------------------------------
/chapter-06/hoc/test/proxy/AddNewPropsHOC.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {shallow} from 'enzyme';
3 |
4 | import addNewPropsHOC from '../../src/proxy/addNewPropsHOC.js';
5 |
6 | describe('addNewPropsHOC', () => {
7 |
8 | const DemoComponent = (props) => {
9 | return (
10 | render something.
11 | );
12 | };
13 |
14 | it('should pass new props to wrapped component', () => {
15 | const NewComponent = addNewPropsHOC(DemoComponent, {foo: 'bar'});
16 | const wrapper = shallow( );
17 | const expectedComponent =
18 |
19 | expect(wrapper.contains(expectedComponent)).toEqual(true);
20 | });
21 |
22 | it('should only overrides given props', () => {
23 | const NewComponent = addNewPropsHOC(DemoComponent, {foo: 'bar'});
24 | const wrapper = shallow( );
25 | const expectedComponent =
26 |
27 | expect(wrapper.contains(expectedComponent)).toEqual(true);
28 | });
29 |
30 | });
31 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/Store.js:
--------------------------------------------------------------------------------
1 | //import {createStore, compose} from 'redux';
2 | //const reducer = f => f;
3 | import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
4 | import {routerReducer} from 'react-router-redux';
5 |
6 | import resetEnhancer from './enhancer/reset.js';
7 |
8 | const configureStore = () => {
9 | const originalReducers = {
10 | routing: routerReducer
11 | }
12 | const reducer = combineReducers(originalReducers);
13 |
14 | const win = global.window;
15 |
16 | const middlewares = [];
17 | if (process.env.NODE_ENV !== 'production') {
18 | middlewares.push(require('redux-immutable-state-invariant')());
19 | }
20 |
21 | const storeEnhancers = compose(
22 | resetEnhancer,
23 | applyMiddleware(...middlewares),
24 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
25 | );
26 |
27 | const store = createStore(reducer, {}, storeEnhancers);
28 | store._reducers = originalReducers;
29 |
30 | return store;
31 | }
32 |
33 | export {configureStore};
34 |
35 |
--------------------------------------------------------------------------------
/chapter-06/hoc/test/inheritance/OnlyForLoggedInHOC.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {mount} from 'enzyme';
3 |
4 | import onlyForLoggedinHOC from '../../src/inheritance/onlyForLoggedinHOC.js';
5 |
6 | describe('RefsHOC', () => {
7 | class DemoComponent extends React.Component {
8 | render() {
9 | return do something
;
10 | }
11 | }
12 |
13 | const NewComponent = onlyForLoggedinHOC(DemoComponent);
14 |
15 | it('should render inner component if loggedIn', () => {
16 | const wrapper = mount( );
17 |
18 | expect(wrapper.find('div').length).toEqual(1);
19 |
20 | // Since we've using inheritance, DemoComponent is replaced by NewComponent in the
21 | // actual dom tree.
22 | expect(wrapper.contains( )).toEqual(false);
23 | });
24 |
25 | it('should NOT render inner component if no loggedIn', () => {
26 | const wrapper = mount( );
27 |
28 | expect(wrapper.find('div').length).toEqual(0);
29 | });
30 | });
31 |
32 |
33 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/todos/views/todoList.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react';
2 | import {connect} from 'react-redux';
3 | import TodoItem from './todoItem.js';
4 | import {selectVisibleTodos} from '../selector.js';
5 |
6 | import TransitionGroup from 'react-addons-css-transition-group';
7 | import './todoItem.css';
8 |
9 | const TodoList = ({todos}) => {
10 | return (
11 |
12 |
13 | {
14 | todos.map((item) => (
15 |
21 | ))
22 | }
23 |
24 |
25 | );
26 | };
27 |
28 | TodoList.propTypes = {
29 | todos: PropTypes.array.isRequired
30 | };
31 |
32 | const mapStateToProps = (state) => {
33 | return {
34 | todos: selectVisibleTodos(state)
35 | };
36 | }
37 |
38 | export default connect(mapStateToProps)(TodoList);
39 |
--------------------------------------------------------------------------------
/chapter-04/todo/src/filter/views/link.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react';
2 | import {connect} from 'react-redux';
3 | import {setFilter} from '../actions.js';
4 |
5 | const Link = ({active, children, onClick}) => {
6 | if (active) {
7 | return {children} ;
8 | } else {
9 | return (
10 | {
11 | ev.preventDefault();
12 | onClick();
13 | }}>
14 | {children}
15 |
16 | );
17 | }
18 | };
19 |
20 | Link.propTypes = {
21 | active: PropTypes.bool.isRequired,
22 | children: PropTypes.node.isRequired,
23 | onClick: PropTypes.func.isRequired
24 | };
25 |
26 | const mapStateToProps = (state, ownProps) => {
27 | return {
28 | active: state.filter === ownProps.filter
29 | }
30 | };
31 |
32 | const mapDispatchToProps = (dispatch, ownProps) => ({
33 | onClick: () => {
34 | dispatch(setFilter(ownProps.filter));
35 | }
36 | });
37 |
38 | export default connect(mapStateToProps, mapDispatchToProps)(Link);
39 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/filter/views/link.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react';
2 | import {connect} from 'react-redux';
3 | import {setFilter} from '../actions.js';
4 |
5 | const Link = ({active, children, onClick}) => {
6 | if (active) {
7 | return {children} ;
8 | } else {
9 | return (
10 | {
11 | ev.preventDefault();
12 | onClick();
13 | }}>
14 | {children}
15 |
16 | );
17 | }
18 | };
19 |
20 | Link.propTypes = {
21 | active: PropTypes.bool.isRequired,
22 | children: PropTypes.node.isRequired,
23 | onClick: PropTypes.func.isRequired
24 | };
25 |
26 | const mapStateToProps = (state, ownProps) => {
27 | return {
28 | active: state.filter === ownProps.filter
29 | }
30 | };
31 |
32 | const mapDispatchToProps = (dispatch, ownProps) => ({
33 | onClick: () => {
34 | dispatch(setFilter(ownProps.filter));
35 | }
36 | });
37 |
38 | export default connect(mapStateToProps, mapDispatchToProps)(Link);
39 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/filter/views/link.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react';
2 | import {connect} from 'react-redux';
3 | import {setFilter} from '../actions.js';
4 |
5 | const Link = ({active, children, onClick}) => {
6 | if (active) {
7 | return {children} ;
8 | } else {
9 | return (
10 | {
11 | ev.preventDefault();
12 | onClick();
13 | }}>
14 | {children}
15 |
16 | );
17 | }
18 | };
19 |
20 | Link.propTypes = {
21 | active: PropTypes.bool.isRequired,
22 | children: PropTypes.node.isRequired,
23 | onClick: PropTypes.func.isRequired
24 | };
25 |
26 | const mapStateToProps = (state, ownProps) => {
27 | return {
28 | active: state.filter === ownProps.filter
29 | }
30 | };
31 |
32 | const mapDispatchToProps = (dispatch, ownProps) => ({
33 | onClick: () => {
34 | dispatch(setFilter(ownProps.filter));
35 | }
36 | });
37 |
38 | export default connect(mapStateToProps, mapDispatchToProps)(Link);
39 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/filter/views/link.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react';
2 | import {connect} from 'react-redux';
3 | import {setFilter} from '../actions.js';
4 |
5 | const Link = ({active, children, onClick}) => {
6 | if (active) {
7 | return {children} ;
8 | } else {
9 | return (
10 | {
11 | ev.preventDefault();
12 | onClick();
13 | }}>
14 | {children}
15 |
16 | );
17 | }
18 | };
19 |
20 | Link.propTypes = {
21 | active: PropTypes.bool.isRequired,
22 | children: PropTypes.node.isRequired,
23 | onClick: PropTypes.func.isRequired
24 | };
25 |
26 | const mapStateToProps = (state, ownProps) => {
27 | return {
28 | active: state.filter === ownProps.filter
29 | }
30 | };
31 |
32 | const mapDispatchToProps = (dispatch, ownProps) => ({
33 | onClick: () => {
34 | dispatch(setFilter(ownProps.filter));
35 | }
36 | });
37 |
38 | export default connect(mapStateToProps, mapDispatchToProps)(Link);
39 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/filter/views/link.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react';
2 | import {connect} from 'react-redux';
3 | import {setFilter} from '../actions.js';
4 |
5 | const Link = ({active, children, onClick}) => {
6 | if (active) {
7 | return {children} ;
8 | } else {
9 | return (
10 | {
11 | ev.preventDefault();
12 | onClick();
13 | }}>
14 | {children}
15 |
16 | );
17 | }
18 | };
19 |
20 | Link.propTypes = {
21 | active: PropTypes.bool.isRequired,
22 | children: PropTypes.node.isRequired,
23 | onClick: PropTypes.func.isRequired
24 | };
25 |
26 | const mapStateToProps = (state, ownProps) => {
27 | return {
28 | active: state.filter === ownProps.filter
29 | }
30 | };
31 |
32 | const mapDispatchToProps = (dispatch, ownProps) => ({
33 | onClick: () => {
34 | dispatch(setFilter(ownProps.filter));
35 | }
36 | });
37 |
38 | export default connect(mapStateToProps, mapDispatchToProps)(Link);
39 |
--------------------------------------------------------------------------------
/chapter-04/todo_controlled_component/src/filter/views/link.js:
--------------------------------------------------------------------------------
1 | import React, {PropTypes} from 'react';
2 | import {connect} from 'react-redux';
3 | import {setFilter} from '../actions.js';
4 |
5 | const Link = ({active, children, onClick}) => {
6 | if (active) {
7 | return {children} ;
8 | } else {
9 | return (
10 | {
11 | ev.preventDefault();
12 | onClick();
13 | }}>
14 | {children}
15 |
16 | );
17 | }
18 | };
19 |
20 | Link.propTypes = {
21 | active: PropTypes.bool.isRequired,
22 | children: PropTypes.node.isRequired,
23 | onClick: PropTypes.func.isRequired
24 | };
25 |
26 | const mapStateToProps = (state, ownProps) => {
27 | return {
28 | active: state.filter === ownProps.filter
29 | }
30 | };
31 |
32 | const mapDispatchToProps = (dispatch, ownProps) => ({
33 | onClick: () => {
34 | dispatch(setFilter(ownProps.filter));
35 | }
36 | });
37 |
38 | export default connect(mapStateToProps, mapDispatchToProps)(Link);
39 |
--------------------------------------------------------------------------------
/chapter-10/animation_types/simulate_requestAnimationFrame.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
13 |
14 |
15 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/chapter-06/hoc/test/proxy/ConnectHOC.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {mount} from 'enzyme';
3 |
4 | import {createStore} from 'redux';
5 | import {Provider} from 'react-redux';
6 |
7 | import connectHOC from '../../src/proxy/connectHOC.js';
8 |
9 | describe('connectHOC', () => {
10 | class DemoComponent extends React.Component {
11 | render() {
12 | return anything
;
13 | }
14 | }
15 |
16 | it('should pass mapped props', () => {
17 | const mapState = (state) => ({
18 | foo: state.foo
19 | });
20 | const connector = connectHOC(mapState);
21 | const Container = connector(DemoComponent);
22 | const initialState = {foo: 'bar'};
23 | const store = createStore(f=>f, initialState);
24 | const wrapper = mount(
25 |
26 |
27 |
28 | );
29 |
30 | expect(wrapper.find('DemoComponent').props()).toEqual({
31 | foo: 'bar'
32 | });
33 |
34 | expect(Container.displayName).toEqual('Connect(DemoComponent)');
35 |
36 | });
37 |
38 | });
39 |
40 |
41 |
--------------------------------------------------------------------------------
/chapter-09/reset_enhancer/test/reset.test.js:
--------------------------------------------------------------------------------
1 | import resetEnhancer from '../src/reset.js';
2 | import {createStore} from 'redux';
3 |
4 | describe('reset enhancer', () => {
5 | const configureStore = (reducer) => {
6 | return createStore(reducer, resetEnhancer);
7 | };
8 |
9 | let store;
10 |
11 | beforeEach(() => {
12 | const reducer = (state, action) => ({payload: action.payload});
13 | store = configureStore(reducer);
14 | });
15 |
16 | it('should not break store functionality', () => {
17 | store.dispatch({type: 'any', payload: 'bar'});
18 |
19 | expect(store.getState()).toEqual({payload: 'bar'});
20 | });
21 |
22 | it('reset', () => {
23 | it('should reset state and reducer', () => {
24 | const newReducer = (state, action) =>({newPayload: action.payload});
25 | const newState = {newPayload: 'new'};
26 |
27 | store.reset(newReducer, newState);
28 | expect(store.getState()).toEqual(newState);
29 |
30 | store.dispatch({type: 'any', payload: 'changed'});
31 | expect(store.getState()).toEqual({newPayload: 'changed'});
32 | });
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/chapter-07/weather_redux/src/weather/actions.js:
--------------------------------------------------------------------------------
1 | import {FETCH_STARTED, FETCH_SUCCESS, FETCH_FAILURE} from './actionTypes.js';
2 |
3 | export const fetchWeatherStarted = () => ({
4 | type: FETCH_STARTED
5 | });
6 |
7 | export const fetchWeatherSuccess = (result) => ({
8 | type: FETCH_SUCCESS,
9 | result
10 | })
11 |
12 | export const fetchWeatherFailure = (error) => ({
13 | type: FETCH_FAILURE,
14 | error
15 | })
16 |
17 | export const fetchWeather = (cityCode) => {
18 | return (dispatch) => {
19 | const apiUrl = `/data/cityinfo/${cityCode}.html`;
20 |
21 | dispatch(fetchWeatherStarted())
22 |
23 | return fetch(apiUrl).then((response) => {
24 | if (response.status !== 200) {
25 | throw new Error('Fail to get response with status ' + response.status);
26 | }
27 |
28 | response.json().then((responseJson) => {
29 | dispatch(fetchWeatherSuccess(responseJson.weatherinfo));
30 | }).catch((error) => {
31 | dispatch(fetchWeatherFailure(error));
32 | });
33 | }).catch((error) => {
34 | dispatch(fetchWeatherFailure(error));
35 | })
36 | };
37 | }
38 |
39 |
40 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/src/components/Counter/view.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import {bindActionCreators} from 'redux';
3 | import {increment, decrement} from './actions.js';
4 | import {connect} from 'react-redux';
5 |
6 | const buttonStyle = {
7 | margin: '10px'
8 | };
9 |
10 | export const stateKey = 'counter';
11 |
12 | function Counter({onIncrement, onDecrement, value}) {
13 | return (
14 |
15 | +
16 | -
17 | Count: {value}
18 |
19 | );
20 | }
21 |
22 | Counter.propTypes = {
23 | onIncrement: PropTypes.func.isRequired,
24 | onDecrement: PropTypes.func.isRequired,
25 | value: PropTypes.number.isRequired
26 | };
27 |
28 | const mapStateToProps = (state) => ({
29 | value: state[stateKey] || 0
30 | })
31 |
32 | const mapDispatchToProps = (dispatch) => bindActionCreators({
33 | onIncrement: increment,
34 | onDecrement: decrement
35 | }, dispatch);
36 |
37 | export default connect(mapStateToProps, mapDispatchToProps)(Counter);
38 |
39 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/src/components/Counter/view.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import {bindActionCreators} from 'redux';
3 | import {increment, decrement} from './actions.js';
4 | import {connect} from 'react-redux';
5 |
6 | const buttonStyle = {
7 | margin: '10px'
8 | };
9 |
10 | export const stateKey = 'counter';
11 |
12 | function Counter({onIncrement, onDecrement, value}) {
13 | return (
14 |
15 | +
16 | -
17 | Count: {value}
18 |
19 | );
20 | }
21 |
22 | Counter.propTypes = {
23 | onIncrement: PropTypes.func.isRequired,
24 | onDecrement: PropTypes.func.isRequired,
25 | value: PropTypes.number.isRequired
26 | };
27 |
28 | const mapStateToProps = (state) => ({
29 | value: state[stateKey] || 0
30 | })
31 |
32 | const mapDispatchToProps = (dispatch) => bindActionCreators({
33 | onIncrement: increment,
34 | onDecrement: decrement
35 | }, dispatch);
36 |
37 | export default connect(mapStateToProps, mapDispatchToProps)(Counter);
38 |
39 |
--------------------------------------------------------------------------------
/chapter-12/express_server/src/components/Counter/view.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 | import {bindActionCreators} from 'redux';
3 | import {increment, decrement} from './actions.js';
4 | import {connect} from 'react-redux';
5 |
6 | const buttonStyle = {
7 | margin: '10px'
8 | };
9 |
10 | export const stateKey = 'counter';
11 |
12 | function Counter({onIncrement, onDecrement, value}) {
13 | return (
14 |
15 | +
16 | -
17 | Count: {value}
18 |
19 | );
20 | }
21 |
22 | Counter.propTypes = {
23 | onIncrement: PropTypes.func.isRequired,
24 | onDecrement: PropTypes.func.isRequired,
25 | value: PropTypes.number.isRequired
26 | };
27 |
28 | const mapStateToProps = (state) => ({
29 | value: state[stateKey] || 0
30 | })
31 |
32 | const mapDispatchToProps = (dispatch) => bindActionCreators({
33 | onIncrement: increment,
34 | onDecrement: decrement
35 | }, dispatch);
36 |
37 | export default connect(mapStateToProps, mapDispatchToProps)(Counter);
38 |
39 |
--------------------------------------------------------------------------------
/chapter-11/react_router_basic/src/Routes.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Router, Route, IndexRoute, browserHistory} from 'react-router';
3 | import {Provider} from 'react-redux';
4 |
5 | import {syncHistoryWithStore} from 'react-router-redux';
6 |
7 | import App from './pages/App.js';
8 | import Home from './pages/Home.js';
9 | import About from './pages/About.js';
10 | import NotFound from './pages/NotFound.js';
11 | import store from './Store.js';
12 |
13 | const createElement = (Component, props) => {
14 | return (
15 |
16 |
17 |
18 | );
19 | };
20 |
21 | const history = syncHistoryWithStore(browserHistory, store);
22 | //const history = browserHistory;
23 |
24 | const Routes = () => (
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | );
34 |
35 | export default Routes;
36 |
--------------------------------------------------------------------------------
/chapter-12/isomorphic/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Suppress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI or in coverage mode
14 | if (!process.env.CI && argv.indexOf('--coverage') < 0) {
15 | argv.push('--watch');
16 | }
17 |
18 | // A temporary hack to clear terminal correctly.
19 | // You can remove this after updating to Jest 18 when it's out.
20 | // https://github.com/facebook/jest/pull/2230
21 | var realWrite = process.stdout.write;
22 | var CLEAR = process.platform === 'win32' ? '\x1Bc' : '\x1B[2J\x1B[3J\x1B[H';
23 | process.stdout.write = function(chunk, encoding, callback) {
24 | if (chunk === '\x1B[2J\x1B[H') {
25 | chunk = CLEAR;
26 | }
27 | return realWrite.call(this, chunk, encoding, callback);
28 | };
29 |
30 |
31 | jest.run(argv);
32 |
--------------------------------------------------------------------------------
/chapter-03/redux_basic/src/views/Summary.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 |
3 | import store from '../Store.js';
4 |
5 | class Summary extends Component {
6 | constructor(props) {
7 | super(props);
8 |
9 | this.onChange = this.onChange.bind(this);
10 |
11 | this.state = this.getOwnState();
12 | }
13 |
14 | onChange() {
15 | this.setState(this.getOwnState());
16 | }
17 |
18 | getOwnState() {
19 | const state = store.getState();
20 | let sum = 0;
21 | for (const key in state) {
22 | if (state.hasOwnProperty(key)) {
23 | sum += state[key];
24 | }
25 | }
26 |
27 | return { sum: sum };
28 | }
29 |
30 | shouldComponentUpdate(nextProps, nextState) {
31 | return nextState.sum !== this.state.sum;
32 | }
33 |
34 | componentDidMount() {
35 | store.subscribe(this.onChange);
36 | }
37 |
38 | componentWillUnmount() {
39 | store.unsubscribe(this.onChange);
40 | }
41 |
42 | render() {
43 | const sum = this.state.sum;
44 | return (
45 | Total Count: {sum}
46 | );
47 | }
48 | }
49 |
50 | export default Summary;
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/chapter-12/express_server/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Suppress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI or in coverage mode
14 | if (!process.env.CI && argv.indexOf('--coverage') < 0) {
15 | argv.push('--watch');
16 | }
17 |
18 | // A temporary hack to clear terminal correctly.
19 | // You can remove this after updating to Jest 18 when it's out.
20 | // https://github.com/facebook/jest/pull/2230
21 | var realWrite = process.stdout.write;
22 | var CLEAR = process.platform === 'win32' ? '\x1Bc' : '\x1B[2J\x1B[3J\x1B[H';
23 | process.stdout.write = function(chunk, encoding, callback) {
24 | if (chunk === '\x1B[2J\x1B[H') {
25 | chunk = CLEAR;
26 | }
27 | return realWrite.call(this, chunk, encoding, callback);
28 | };
29 |
30 |
31 | jest.run(argv);
32 |
--------------------------------------------------------------------------------
/chapter-11/chunked_with_redux/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Suppress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI or in coverage mode
14 | if (!process.env.CI && argv.indexOf('--coverage') < 0) {
15 | argv.push('--watch');
16 | }
17 |
18 | // A temporary hack to clear terminal correctly.
19 | // You can remove this after updating to Jest 18 when it's out.
20 | // https://github.com/facebook/jest/pull/2230
21 | var realWrite = process.stdout.write;
22 | var CLEAR = process.platform === 'win32' ? '\x1Bc' : '\x1B[2J\x1B[3J\x1B[H';
23 | process.stdout.write = function(chunk, encoding, callback) {
24 | if (chunk === '\x1B[2J\x1B[H') {
25 | chunk = CLEAR;
26 | }
27 | return realWrite.call(this, chunk, encoding, callback);
28 | };
29 |
30 |
31 | jest.run(argv);
32 |
--------------------------------------------------------------------------------
/chapter-11/react_router_chunked/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Suppress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI or in coverage mode
14 | if (!process.env.CI && argv.indexOf('--coverage') < 0) {
15 | argv.push('--watch');
16 | }
17 |
18 | // A temporary hack to clear terminal correctly.
19 | // You can remove this after updating to Jest 18 when it's out.
20 | // https://github.com/facebook/jest/pull/2230
21 | var realWrite = process.stdout.write;
22 | var CLEAR = process.platform === 'win32' ? '\x1Bc' : '\x1B[2J\x1B[3J\x1B[H';
23 | process.stdout.write = function(chunk, encoding, callback) {
24 | if (chunk === '\x1B[2J\x1B[H') {
25 | chunk = CLEAR;
26 | }
27 | return realWrite.call(this, chunk, encoding, callback);
28 | };
29 |
30 |
31 | jest.run(argv);
32 |
--------------------------------------------------------------------------------
/chapter-05/todo_perf/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
2 |
3 | import {reducer as todoReducer} from './todos';
4 | import {reducer as filterReducer} from './filter';
5 |
6 | import Perf from 'react-addons-perf'
7 |
8 | const win = window;
9 | win.Perf = Perf
10 |
11 | const reducer = combineReducers({
12 | todos: todoReducer,
13 | filter: filterReducer
14 | });
15 |
16 | const middlewares = [];
17 | if (process.env.NODE_ENV !== 'production') {
18 | middlewares.push(require('redux-immutable-state-invariant')());
19 | }
20 |
21 | const storeEnhancers = compose(
22 | applyMiddleware(...middlewares),
23 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
24 | );
25 |
26 | const initialState = {
27 | todos: [
28 | {
29 | id: 0,
30 | text: 'First',
31 | completed: true
32 | },
33 | {
34 | id: 1,
35 | text: 'Second',
36 | completed: false
37 | },
38 | {
39 | id: 2,
40 | text: 'Third',
41 | completed: true
42 | }
43 | ]
44 |
45 | }
46 | export default createStore(reducer, initialState, storeEnhancers);
47 |
48 |
--------------------------------------------------------------------------------
/chapter-10/todo_animated/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
2 |
3 | import {reducer as todoReducer} from './todos';
4 | import {reducer as filterReducer} from './filter';
5 |
6 | import Perf from 'react-addons-perf'
7 |
8 | const win = window;
9 | win.Perf = Perf
10 |
11 | const reducer = combineReducers({
12 | todos: todoReducer,
13 | filter: filterReducer
14 | });
15 |
16 | const middlewares = [];
17 | if (process.env.NODE_ENV !== 'production') {
18 | middlewares.push(require('redux-immutable-state-invariant')());
19 | }
20 |
21 | const storeEnhancers = compose(
22 | applyMiddleware(...middlewares),
23 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
24 | );
25 |
26 | const initialState = {
27 | todos: [
28 | {
29 | id: 0,
30 | text: 'First',
31 | completed: true
32 | },
33 | {
34 | id: 1,
35 | text: 'Second',
36 | completed: false
37 | },
38 | {
39 | id: 2,
40 | text: 'Third',
41 | completed: true
42 | }
43 | ]
44 |
45 | }
46 | export default createStore(reducer, initialState, storeEnhancers);
47 |
48 |
--------------------------------------------------------------------------------
/chapter-10/todo_react_motion/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
2 |
3 | import {reducer as todoReducer} from './todos';
4 | import {reducer as filterReducer} from './filter';
5 |
6 | import Perf from 'react-addons-perf'
7 |
8 | const win = window;
9 | win.Perf = Perf
10 |
11 | const reducer = combineReducers({
12 | todos: todoReducer,
13 | filter: filterReducer
14 | });
15 |
16 | const middlewares = [];
17 | if (process.env.NODE_ENV !== 'production') {
18 | middlewares.push(require('redux-immutable-state-invariant')());
19 | }
20 |
21 | const storeEnhancers = compose(
22 | applyMiddleware(...middlewares),
23 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
24 | );
25 |
26 | const initialState = {
27 | todos: [
28 | {
29 | id: 0,
30 | text: 'First',
31 | completed: true
32 | },
33 | {
34 | id: 1,
35 | text: 'Second',
36 | completed: false
37 | },
38 | {
39 | id: 2,
40 | text: 'Third',
41 | completed: true
42 | }
43 | ]
44 |
45 | }
46 | export default createStore(reducer, initialState, storeEnhancers);
47 |
48 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/src/Store.js:
--------------------------------------------------------------------------------
1 | import {createStore, combineReducers, applyMiddleware, compose} from 'redux';
2 |
3 | import {reducer as todoReducer} from './todos';
4 | import {reducer as filterReducer} from './filter';
5 |
6 | import Perf from 'react-addons-perf'
7 |
8 | const win = window;
9 | win.Perf = Perf
10 |
11 | const reducer = combineReducers({
12 | todos: todoReducer,
13 | filter: filterReducer
14 | });
15 |
16 | const middlewares = [];
17 | if (process.env.NODE_ENV !== 'production') {
18 | middlewares.push(require('redux-immutable-state-invariant')());
19 | }
20 |
21 | const storeEnhancers = compose(
22 | applyMiddleware(...middlewares),
23 | (win && win.devToolsExtension) ? win.devToolsExtension() : (f) => f,
24 | );
25 |
26 | const initialState = {
27 | todos: [
28 | {
29 | id: 0,
30 | text: 'First',
31 | completed: true
32 | },
33 | {
34 | id: 1,
35 | text: 'Second',
36 | completed: false
37 | },
38 | {
39 | id: 2,
40 | text: 'Third',
41 | completed: true
42 | }
43 | ]
44 |
45 | }
46 | export default createStore(reducer, initialState, storeEnhancers);
47 |
48 |
--------------------------------------------------------------------------------
/chapter-06/function_as_child/src/CountDown.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | class CountDown extends React.Component {
4 |
5 | constructor() {
6 | super(...arguments);
7 |
8 | this.state = {count: this.props.startCount};
9 | }
10 |
11 | shouldComponentUpdate(nextProps, nextState) {
12 | return nextState.count !== this.state.count;
13 | }
14 |
15 | componentDidMount() {
16 | this.intervalHandle = setInterval(() => {
17 | const newCount = this.state.count - 1;
18 | if (newCount >= 0) {
19 | this.setState({count: newCount});
20 | } else {
21 | window.clearInterval(this.intervalHandle);
22 | this.intervalHandle = null;
23 | }
24 | }, 1000);
25 | }
26 |
27 | componentWillUnmount() {
28 | if (this.intervalHandle) {
29 | window.clearInterval(this.intervalHandle);
30 | this.intervalHandle = null;
31 | }
32 | }
33 |
34 | render() {
35 | return this.props.children(this.state.count);
36 | }
37 | }
38 |
39 | CountDown.propTypes = {
40 | children: React.PropTypes.func.isRequired,
41 | startCount: React.PropTypes.number.isRequired
42 | }
43 |
44 | export default CountDown;
45 |
--------------------------------------------------------------------------------
/chapter-03/flux/src/stores/CounterStore.js:
--------------------------------------------------------------------------------
1 | import AppDispatcher from '../AppDispatcher.js';
2 | import * as ActionTypes from '../ActionTypes.js';
3 | import {EventEmitter} from 'events';
4 |
5 | const CHANGE_EVENT = 'changed';
6 |
7 | const counterValues = {
8 | 'First': 0,
9 | 'Second': 10,
10 | 'Third': 30
11 | };
12 |
13 |
14 | const CounterStore = Object.assign({}, EventEmitter.prototype, {
15 | getCounterValues: function() {
16 | return counterValues;
17 | },
18 |
19 | emitChange: function() {
20 | this.emit(CHANGE_EVENT);
21 | },
22 |
23 | addChangeListener: function(callback) {
24 | this.on(CHANGE_EVENT, callback);
25 | },
26 |
27 | removeChangeListener: function(callback) {
28 | this.removeListener(CHANGE_EVENT, callback);
29 | }
30 |
31 | });
32 |
33 | CounterStore.dispatchToken = AppDispatcher.register((action) => {
34 | if (action.type === ActionTypes.INCREMENT) {
35 | counterValues[action.counterCaption] ++;
36 | CounterStore.emitChange();
37 | } else if (action.type === ActionTypes.DECREMENT) {
38 | counterValues[action.counterCaption] --;
39 | CounterStore.emitChange();
40 | }
41 | });
42 |
43 | export default CounterStore;
44 |
--------------------------------------------------------------------------------
/chapter-05/todo_with_selector/test/todos/views/todoList.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {mount} from 'enzyme';
3 | import {createStore, combineReducers} from 'redux';
4 | import {Provider} from 'react-redux';
5 |
6 | import {reducer as todosReducer, actions} from '../../../src/todos/index.js';
7 | import {reducer as filterReducer} from '../../../src/filter/index.js';
8 | import {FilterTypes} from '../../../src/constants.js';
9 | import TodoList from '../../../src/todos/views/todoList.js';
10 | import TodoItem from '../../../src/todos/views/todoItem.js';
11 |
12 | describe('todos', () => {
13 | it('should add new todo-item on addTodo action', () => {
14 | const store = createStore(
15 | combineReducers({
16 | todos: todosReducer,
17 | filter: filterReducer
18 | }), {
19 | todos: [],
20 | filter: FilterTypes.ALL
21 | });
22 | const subject = (
23 |
24 |
25 |
26 | );
27 | const wrapper = mount(subject);
28 |
29 | store.dispatch(actions.addTodo('write more test'));
30 |
31 | expect(wrapper.find('.text').text()).toEqual('write more test');
32 | });
33 |
34 | });
35 |
--------------------------------------------------------------------------------
/chapter-06/hoc/test/inheritance/ModifyPropsHOC.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {mount} from 'enzyme';
3 |
4 | import chai from 'chai';
5 | import chaiEnzyme from 'chai-enzyme';
6 | chai.use(chaiEnzyme());
7 |
8 | const {expect} = chai;
9 |
10 | import modifyPropsHOC from '../../src/inheritance/modifyPropsHOC.js';
11 |
12 | describe('modifyPropsHOC', () => {
13 |
14 | it('should render with modified props as red', () => {
15 | class DivComponent extends React.Component {
16 | render () {
17 | return hello world
;
18 | }
19 | }
20 | const NewComponent = modifyPropsHOC(DivComponent);
21 | const wrapper = mount( );
22 |
23 | expect(wrapper.find('div')).to.have.style('color').equal('red');
24 | });
25 |
26 | it('should render with modified props as green', () => {
27 | class SpanComponent extends React.Component {
28 | render () {
29 | return hello world ;
30 | }
31 | }
32 | const NewComponent = modifyPropsHOC(SpanComponent);
33 | const wrapper = mount( );
34 |
35 | expect(wrapper.find('span')).to.have.style('color').equal('green');
36 | });
37 |
38 |
39 | });
40 |
41 |
42 |
--------------------------------------------------------------------------------
/chapter-02/controlpanel_with_summary/src/ControlPanel.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import Counter from './Counter.js';
3 |
4 | const style = {
5 | margin: '20px'
6 | };
7 |
8 | class ControlPanel extends Component {
9 |
10 | constructor(props) {
11 | super(props);
12 |
13 | this.onCounterUpdate = this.onCounterUpdate.bind(this);
14 |
15 | this.initValues = [ 0, 10, 20];
16 |
17 | const initSum = this.initValues.reduce((a, b) => a+b, 0);
18 | this.state = {
19 | sum: initSum
20 | };
21 | }
22 |
23 | onCounterUpdate(newValue, previousValue) {
24 | const valueChange = newValue - previousValue;
25 | this.setState({ sum: this.state.sum + valueChange});
26 | }
27 |
28 | render() {
29 | return (
30 |
31 |
32 |
33 |
34 |
35 |
Total Count: {this.state.sum}
36 |
37 | );
38 | }
39 | }
40 |
41 | export default ControlPanel;
42 |
43 |
--------------------------------------------------------------------------------
/chapter-03/flux/config/env.js:
--------------------------------------------------------------------------------
1 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
2 | // injected into the application via DefinePlugin in Webpack configuration.
3 |
4 | var REACT_APP = /^REACT_APP_/i;
5 |
6 | function getClientEnvironment(publicUrl) {
7 | var processEnv = Object
8 | .keys(process.env)
9 | .filter(key => REACT_APP.test(key))
10 | .reduce((env, key) => {
11 | env[key] = JSON.stringify(process.env[key]);
12 | return env;
13 | }, {
14 | // Useful for determining whether we’re running in production mode.
15 | // Most importantly, it switches React into the correct mode.
16 | 'NODE_ENV': JSON.stringify(
17 | process.env.NODE_ENV || 'development'
18 | ),
19 | // Useful for resolving the correct path to static assets in `public`.
20 | // For example, .
21 | // This should only be used as an escape hatch. Normally you would put
22 | // images into the `src` and `import` them in code to get their paths.
23 | 'PUBLIC_URL': JSON.stringify(publicUrl)
24 | });
25 | return {'process.env': processEnv};
26 | }
27 |
28 | module.exports = getClientEnvironment;
29 |
--------------------------------------------------------------------------------