├── SUMMARY.md ├── Appendix02 ├── HelloWorldApp │ ├── .watchmanconfig │ ├── android │ │ ├── settings.gradle │ │ ├── app │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── res │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ └── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── helloworldapp │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ └── MainApplication.java │ │ │ │ └── AndroidManifest.xml │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── keystores │ │ │ ├── debug.keystore.properties │ │ │ └── BUCK │ │ ├── build.gradle │ │ └── gradle.properties │ ├── .buckconfig │ ├── package.json │ ├── ios │ │ ├── HelloWorldApp │ │ │ ├── AppDelegate.h │ │ │ ├── main.m │ │ │ ├── Images.xcassets │ │ │ │ └── AppIcon.appiconset │ │ │ │ │ └── Contents.json │ │ │ └── AppDelegate.m │ │ └── HelloWorldAppTests │ │ │ └── Info.plist │ ├── .gitignore │ ├── index.ios.js │ └── index.android.js ├── ReactNativeFirebaseMotto │ ├── .watchmanconfig │ ├── src │ │ ├── store │ │ │ ├── index.js │ │ │ └── configureStore.js │ │ ├── components │ │ │ ├── Main │ │ │ │ ├── index.js │ │ │ │ └── Main.js │ │ │ ├── ToolBar │ │ │ │ ├── index.js │ │ │ │ ├── ToolBar.js │ │ │ │ └── toolBarStyles.js │ │ │ ├── ListItem │ │ │ │ ├── index.js │ │ │ │ ├── listItemStyles.js │ │ │ │ └── ListItem.js │ │ │ ├── ActionButton │ │ │ │ ├── index.js │ │ │ │ ├── actionButtonStyles.js │ │ │ │ └── ActionButton.js │ │ │ ├── InputModal │ │ │ │ ├── index.js │ │ │ │ ├── inputModelStyles.js │ │ │ │ └── InputModal.js │ │ │ └── MottoList │ │ │ │ ├── index.js │ │ │ │ └── mottoStyles.js │ │ ├── actions │ │ │ ├── index.js │ │ │ ├── uiActions.js │ │ │ └── mottoActions.js │ │ ├── containers │ │ │ ├── InputModalContainer │ │ │ │ ├── index.js │ │ │ │ └── InputModalContainer.js │ │ │ ├── MottoListContainer │ │ │ │ ├── index.js │ │ │ │ └── MottoListContainer.js │ │ │ └── ActionButtonContainer │ │ │ │ ├── index.js │ │ │ │ └── ActionButtonContainer.js │ │ ├── constants │ │ │ ├── config.js │ │ │ ├── actionTypes.js │ │ │ └── models.js │ │ └── reducers │ │ │ ├── index.js │ │ │ ├── ui │ │ │ └── uiReducers.js │ │ │ └── data │ │ │ └── mottoReducers.js │ ├── android │ │ ├── settings.gradle │ │ ├── app │ │ │ └── src │ │ │ │ └── main │ │ │ │ ├── res │ │ │ │ ├── values │ │ │ │ │ ├── strings.xml │ │ │ │ │ └── styles.xml │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ └── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── reactnativefirebasemotto │ │ │ │ │ ├── MainActivity.java │ │ │ │ │ └── MainApplication.java │ │ │ │ └── AndroidManifest.xml │ │ ├── keystores │ │ │ ├── debug.keystore.properties │ │ │ └── BUCK │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── build.gradle │ │ └── gradle.properties │ ├── .babelrc │ ├── .buckconfig │ ├── .eslintrc │ ├── index.android.js │ ├── ios │ │ ├── ReactNativeFirebaseMotto │ │ │ ├── AppDelegate.h │ │ │ ├── main.m │ │ │ └── Images.xcassets │ │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ └── ReactNativeFirebaseMottoTests │ │ │ └── Info.plist │ ├── index.ios.js │ ├── .gitignore │ └── package.json └── images │ ├── demo-1.png │ ├── demo-2.png │ ├── android-1.png │ ├── android-2.png │ ├── android-3.png │ ├── android-4.png │ ├── flexbox-1.png │ ├── folder-1.png │ ├── folder-2.png │ ├── align-items.png │ ├── firebase-init.png │ ├── firebase-landing.png │ ├── justify-content.png │ ├── firebase-dashboard.png │ ├── firebase-database-0.png │ ├── firebase-database-1.png │ ├── firebase-database-2.png │ ├── react-native-logo.png │ ├── react-native-init-app.png │ ├── react-native-terminal.png │ ├── flexbox-flex-direction.png │ └── react-native-init-app-reload.png ├── .gitignore ├── Appendix03 ├── react-redux-test-example │ ├── test │ │ ├── actionTest.js │ │ └── reducerTest.test.js │ ├── src │ │ ├── actions │ │ │ ├── index.js │ │ │ └── todoActions.js │ │ ├── components │ │ │ ├── Main │ │ │ │ ├── index.js │ │ │ │ └── Main.js │ │ │ ├── TodoList │ │ │ │ ├── index.js │ │ │ │ └── TodoList.js │ │ │ └── TodoHeader │ │ │ │ ├── index.js │ │ │ │ └── TodoHeader.js │ │ ├── store │ │ │ ├── index.js │ │ │ └── configureStore.js │ │ ├── containers │ │ │ ├── TodoListContainer │ │ │ │ ├── index.js │ │ │ │ └── TodoListContainer.js │ │ │ └── TodoHeaderContainer │ │ │ │ ├── index.js │ │ │ │ └── TodoHeaderContainer.js │ │ ├── constants │ │ │ ├── actionTypes.js │ │ │ └── models.js │ │ ├── index.html │ │ ├── reducers │ │ │ ├── ui │ │ │ │ └── uiReducers.js │ │ │ ├── index.js │ │ │ └── data │ │ │ │ └── todoReducers.js │ │ └── index.js │ ├── .babelrc │ ├── .eslintrc │ ├── README.md │ ├── dist │ │ └── index.html │ ├── webpack.config.js │ └── package.json ├── react-mocha-test-example │ ├── test │ │ ├── mocha.opts │ │ ├── add.test.js │ │ ├── promise.test.js │ │ └── async.test.js │ ├── src │ │ ├── components │ │ │ └── Main │ │ │ │ ├── index.js │ │ │ │ └── Main.js │ │ ├── modules │ │ │ └── add.js │ │ ├── index.html │ │ └── index.js │ ├── .babelrc │ ├── .eslintrc │ ├── webpack.config.js │ └── package.json ├── react-addons-test-utils-example │ ├── src │ │ ├── components │ │ │ ├── Main │ │ │ │ ├── index.js │ │ │ │ └── Main.js │ │ │ ├── TodoList │ │ │ │ ├── index.js │ │ │ │ └── TodoList.js │ │ │ └── TodoHeader │ │ │ │ ├── index.js │ │ │ │ └── TodoHeader.js │ │ ├── index.html │ │ └── index.js │ ├── .babelrc │ ├── .eslint │ ├── test │ │ ├── setup.js │ │ ├── enzyme │ │ │ ├── shallowRender.test.js │ │ │ ├── staticRender.test.js │ │ │ └── mount.test.js │ │ ├── shallowRender.test.js │ │ ├── renderIntoDocument.test.js │ │ └── shallowRenderProps.test.js │ ├── webpack.config.js │ └── package.json └── images │ └── mocha.png ├── Ch07 ├── react-redux-example │ ├── src │ │ ├── actions │ │ │ ├── index.js │ │ │ └── todoActions.js │ │ ├── components │ │ │ ├── Main │ │ │ │ ├── index.js │ │ │ │ └── Main.js │ │ │ ├── TodoHeader │ │ │ │ ├── index.js │ │ │ │ └── TodoHeader.js │ │ │ └── TodoList │ │ │ │ ├── index.js │ │ │ │ └── TodoList.js │ │ ├── store │ │ │ ├── index.js │ │ │ └── configureStore.js │ │ ├── containers │ │ │ ├── TodoListContainer │ │ │ │ ├── index.js │ │ │ │ └── TodoListContainer.js │ │ │ └── TodoHeaderContainer │ │ │ │ ├── index.js │ │ │ │ └── TodoHeaderContainer.js │ │ ├── constants │ │ │ ├── actionTypes.js │ │ │ └── models.js │ │ ├── index.html │ │ ├── reducers │ │ │ ├── ui │ │ │ │ └── uiReducers.js │ │ │ ├── index.js │ │ │ └── data │ │ │ │ └── todoReducers.js │ │ └── index.js │ ├── .babelrc │ ├── README.md │ ├── dist │ │ └── index.html │ ├── .eslintrc │ ├── webpack.config.js │ └── package.json ├── react-flux-example │ ├── src │ │ ├── constants │ │ │ └── actionTypes.js │ │ ├── components │ │ │ ├── TodoList │ │ │ │ ├── index.js │ │ │ │ └── TodoList.js │ │ │ └── TodoHeader │ │ │ │ ├── index.js │ │ │ │ └── TodoHeader.js │ │ ├── index.html │ │ ├── actions │ │ │ └── todoActions.js │ │ ├── dispatcher │ │ │ └── AppDispatcher.js │ │ ├── index.js │ │ └── stores │ │ │ └── TodoStore.js │ ├── .babelrc │ ├── .eslintrc │ ├── dist │ │ └── index.html │ ├── webpack.config.js │ └── package.json ├── images │ ├── folder.png │ ├── flux-demo.png │ ├── flux-react.png │ ├── redux-flow.png │ ├── redux-logo.png │ ├── react-flux.jpeg │ ├── redux-folder.png │ ├── redux-store.png │ ├── using-redux.jpg │ ├── redux-flowchart.png │ ├── react-redux-demo.png │ ├── flux-simple-diagram.png │ ├── react-flux-diagram.png │ ├── react-redux-dev-demo.png │ ├── react-redux-diagram.png │ └── using-redux-compare.jpg └── README.md ├── cover.png ├── Ch05 ├── react-router-example │ ├── res │ │ └── styles │ │ │ └── main.css │ ├── src │ │ ├── components │ │ │ ├── App │ │ │ │ ├── index.js │ │ │ │ ├── appStyles.js │ │ │ │ └── App.js │ │ │ ├── Home │ │ │ │ ├── index.js │ │ │ │ └── Home.js │ │ │ ├── User │ │ │ │ ├── index.js │ │ │ │ └── User.js │ │ │ ├── About │ │ │ │ ├── index.js │ │ │ │ └── About.js │ │ │ ├── NavLink │ │ │ │ ├── index.js │ │ │ │ └── NavLink.js │ │ │ ├── Repos │ │ │ │ ├── index.js │ │ │ │ └── Repos.js │ │ │ └── Contacts │ │ │ │ ├── index.js │ │ │ │ └── Contacts.js │ │ ├── index.html │ │ └── index.js │ ├── .babelrc │ ├── .eslintrc │ ├── webpack.config.js │ └── package.json ├── images │ ├── example.png │ ├── folder.png │ └── react-router.jpg └── README.md ├── Ch09 ├── react-router-redux-github-finder │ ├── README.md │ ├── src │ │ ├── components │ │ │ ├── Main │ │ │ │ ├── index.js │ │ │ │ └── Main.js │ │ │ ├── HomePage │ │ │ │ ├── index.js │ │ │ │ └── HomePage.js │ │ │ ├── GithubBox │ │ │ │ ├── index.js │ │ │ │ └── GithubBox.js │ │ │ └── ResultPage │ │ │ │ ├── index.js │ │ │ │ └── ResultPage.js │ │ ├── store │ │ │ ├── index.js │ │ │ └── configureStore.js │ │ ├── actions │ │ │ ├── index.js │ │ │ ├── uiActions.js │ │ │ └── githubActions.js │ │ ├── containers │ │ │ ├── HomePageContainer │ │ │ │ ├── index.js │ │ │ │ └── HomePageContainer.js │ │ │ └── ResultPageContainer │ │ │ │ ├── index.js │ │ │ │ └── ResultPageContainer.js │ │ ├── constants │ │ │ ├── models.js │ │ │ └── actionTypes.js │ │ ├── index.html │ │ ├── reducers │ │ │ ├── index.js │ │ │ ├── ui │ │ │ │ └── uiReducers.js │ │ │ └── data │ │ │ │ └── githubReducers.js │ │ └── index.js │ ├── .babelrc │ ├── res │ │ └── images │ │ │ └── github.png │ ├── dist │ │ └── index.html │ ├── .eslintrc │ ├── webpack.config.js │ └── package.json ├── images │ ├── demo-1.png │ └── demo-2.png └── README.md ├── cc-by-nc-sa.png ├── Ch03 ├── todo-examples │ ├── app │ │ ├── components │ │ │ ├── TodoList │ │ │ │ ├── index.js │ │ │ │ ├── todoListStyles.js │ │ │ │ └── TodoList.js │ │ │ └── TodoHeader │ │ │ │ ├── index.js │ │ │ │ ├── todoHeaderStyles.js │ │ │ │ └── TodoHeader.js │ │ ├── index.html │ │ └── index.js │ ├── .babelrc │ ├── dist │ │ └── index.html │ ├── .eslintrc.js │ ├── gulpfile.js │ ├── webpack.config.js │ ├── .gitignore │ └── package.json ├── images │ ├── fb_like.jpg │ ├── reactjs.png │ └── component.png └── README.md ├── Ch02 ├── images │ ├── react.png │ ├── hello-world.png │ ├── react-browserify-gulp.png │ ├── webpack-module-bundler.png │ ├── browserify-folder-pregulp.png │ ├── react-webpack-browserify.png │ └── browserify-folder-possgulp.png ├── browserify-example │ ├── .babelrc │ ├── index.html │ ├── dist │ │ └── index.html │ ├── app │ │ └── index.js │ └── package.json ├── webpack-example │ ├── .babelrc │ ├── app │ │ ├── index.html │ │ └── index.js │ ├── dist │ │ └── index.html │ ├── package.json │ └── webpack.config.js ├── README.md └── cdn-example │ └── hello.html ├── Ch10 ├── react-redux-server-rendering │ ├── common │ │ ├── actions │ │ │ ├── index.js │ │ │ └── counterActions.js │ │ ├── store │ │ │ ├── index.js │ │ │ └── configureStore.js │ │ ├── components │ │ │ └── Counter │ │ │ │ ├── index.js │ │ │ │ └── Counter.js │ │ ├── containers │ │ │ └── CounterContainer │ │ │ │ ├── index.js │ │ │ │ └── CounterContainer.js │ │ ├── constants │ │ │ ├── actionTypes.js │ │ │ └── models.js │ │ ├── reducers │ │ │ ├── index.js │ │ │ └── counterReducers.js │ │ └── api │ │ │ └── counter.js │ ├── .babelrc │ ├── server │ │ └── index.js │ ├── .eslintrc │ ├── README.md │ ├── client │ │ └── index.js │ ├── webpack.config.js │ └── package.json ├── images │ ├── client-mvc.png │ ├── isomorphic-api.png │ ├── client-server-mvc.png │ ├── open-cook-demo-1.png │ ├── open-cook-demo-2.png │ ├── open-cook-demo-3.png │ ├── open-cook-demo-4.png │ ├── isomorphic-javascript.png │ ├── open-cook-demo-folder.png │ ├── react-server-rendering-demo.png │ └── react-server-rendering-folder.png ├── react-router-redux-node-isomorphic-open-cook │ ├── src │ │ ├── common │ │ │ ├── components │ │ │ │ ├── Main │ │ │ │ │ ├── index.js │ │ │ │ │ └── Main.js │ │ │ │ ├── AppBar │ │ │ │ │ ├── index.js │ │ │ │ │ └── AppBar.js │ │ │ │ ├── CheckAuth │ │ │ │ │ ├── index.js │ │ │ │ │ └── CheckAuth.js │ │ │ │ ├── HomePage │ │ │ │ │ ├── index.js │ │ │ │ │ └── HomePage.js │ │ │ │ ├── LoginBox │ │ │ │ │ ├── index.js │ │ │ │ │ └── LoginBox.js │ │ │ │ ├── LoginPage │ │ │ │ │ ├── index.js │ │ │ │ │ └── LoginPage.js │ │ │ │ ├── RecipeBox │ │ │ │ │ ├── index.js │ │ │ │ │ └── RecipeBox.js │ │ │ │ ├── ShareBox │ │ │ │ │ └── index.js │ │ │ │ └── SharePage │ │ │ │ │ ├── index.js │ │ │ │ │ └── SharePage.js │ │ │ ├── store │ │ │ │ ├── index.js │ │ │ │ └── configureStore.js │ │ │ ├── containers │ │ │ │ ├── AppBarContainer │ │ │ │ │ ├── index.js │ │ │ │ │ └── AppBarContainer.js │ │ │ │ ├── HomePageContainer │ │ │ │ │ ├── index.js │ │ │ │ │ └── HomePageContainer.js │ │ │ │ ├── LoginBoxContainer │ │ │ │ │ ├── index.js │ │ │ │ │ └── LoginBoxContainer.js │ │ │ │ ├── LoginPageContainer │ │ │ │ │ ├── index.js │ │ │ │ │ └── LoginPageContainer.js │ │ │ │ ├── RecipeBoxContainer │ │ │ │ │ ├── index.js │ │ │ │ │ └── RecipeBoxContainer.js │ │ │ │ ├── ShareBoxContainer │ │ │ │ │ └── index.js │ │ │ │ └── SharePageContainer │ │ │ │ │ ├── index.js │ │ │ │ │ └── SharePageContainer.js │ │ │ ├── actions │ │ │ │ ├── index.js │ │ │ │ ├── uiActions.js │ │ │ │ ├── recipeActions.js │ │ │ │ └── userActions.js │ │ │ ├── utils │ │ │ │ └── fetchComponentData.js │ │ │ ├── reducers │ │ │ │ ├── index.js │ │ │ │ ├── data │ │ │ │ │ ├── recipeReducers.js │ │ │ │ │ └── userReducers.js │ │ │ │ └── ui │ │ │ │ │ └── uiReducers.js │ │ │ ├── constants │ │ │ │ ├── models.js │ │ │ │ └── actionTypes.js │ │ │ └── routes │ │ │ │ └── index.js │ │ ├── server │ │ │ ├── index.js │ │ │ ├── config │ │ │ │ └── index.js │ │ │ ├── public │ │ │ │ └── images │ │ │ │ │ └── loading.gif │ │ │ └── models │ │ │ │ ├── user.js │ │ │ │ └── recipe.js │ │ └── client │ │ │ └── index.js │ ├── .babelrc │ ├── .eslintrc │ └── webpack.config.js └── README.md ├── Ch01 ├── images │ ├── frameworks.png │ ├── html-css-js.png │ └── react-eco-wp.gif └── README.md ├── Ch06 ├── images │ └── immutable.png └── README.md ├── Appendix01 └── images │ └── react-es6.jpg ├── Ch04 ├── images │ └── react-lifecycle.png └── README.md ├── Appendix04 ├── graphql-example │ ├── .babelrc │ ├── index.js │ ├── .eslintrc │ ├── data.json │ └── package.json └── images │ ├── graphql-demo-1.png │ ├── graphql-demo-2.png │ ├── relay-graphql.png │ └── relay-architecture.png └── Ch08 └── README.md /SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/.watchmanconfig: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/test/actionTest.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/test/reducerTest.test.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/actions/index.js: -------------------------------------------------------------------------------- 1 | export * from './todoActions'; -------------------------------------------------------------------------------- /cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/cover.png -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/test/mocha.opts: -------------------------------------------------------------------------------- 1 | --watch 2 | --reporter spec 3 | -------------------------------------------------------------------------------- /Ch05/react-router-example/res/styles/main.css: -------------------------------------------------------------------------------- 1 | .active { 2 | color: orange; 3 | } -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/README.md: -------------------------------------------------------------------------------- 1 | # React Router Redux Github Finder -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/actions/index.js: -------------------------------------------------------------------------------- 1 | export * from './todoActions'; -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/components/Main/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Main'; -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/store/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './configureStore'; -------------------------------------------------------------------------------- /cc-by-nc-sa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/cc-by-nc-sa.png -------------------------------------------------------------------------------- /Ch03/todo-examples/app/components/TodoList/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoList'; 2 | -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/App/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './App'; 2 | -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/Home/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Home'; 2 | -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/User/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './User'; 2 | -------------------------------------------------------------------------------- /Ch07/react-flux-example/src/constants/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const ADD_TODO = 'ADD_TODO'; 2 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/store/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './configureStore'; -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/components/Main/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Main'; -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/store/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './configureStore'; -------------------------------------------------------------------------------- /Ch02/images/react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch02/images/react.png -------------------------------------------------------------------------------- /Ch03/todo-examples/app/components/TodoHeader/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoHeader'; 2 | -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/About/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './About'; 2 | -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/NavLink/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './NavLink'; 2 | -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/Repos/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Repos'; 2 | -------------------------------------------------------------------------------- /Ch07/react-flux-example/src/components/TodoList/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoList'; 2 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/components/TodoHeader/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoHeader'; -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/components/TodoList/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoList'; -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/actions/index.js: -------------------------------------------------------------------------------- 1 | export * from './counterActions'; 2 | -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/store/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './configureStore'; -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/Main/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Main'; 2 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/ToolBar/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './ToolBar'; -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/src/components/Main/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Main'; 2 | -------------------------------------------------------------------------------- /Ch03/images/fb_like.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch03/images/fb_like.jpg -------------------------------------------------------------------------------- /Ch03/images/reactjs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch03/images/reactjs.png -------------------------------------------------------------------------------- /Ch05/images/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch05/images/example.png -------------------------------------------------------------------------------- /Ch05/images/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch05/images/folder.png -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/Contacts/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Contacts'; 2 | -------------------------------------------------------------------------------- /Ch07/images/folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/folder.png -------------------------------------------------------------------------------- /Ch07/react-flux-example/src/components/TodoHeader/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoHeader'; 2 | -------------------------------------------------------------------------------- /Ch09/images/demo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch09/images/demo-1.png -------------------------------------------------------------------------------- /Ch09/images/demo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch09/images/demo-2.png -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/ListItem/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './ListItem'; -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/src/components/Main/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Main'; -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/components/TodoList/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoList'; -------------------------------------------------------------------------------- /Ch01/images/frameworks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch01/images/frameworks.png -------------------------------------------------------------------------------- /Ch03/images/component.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch03/images/component.png -------------------------------------------------------------------------------- /Ch06/images/immutable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch06/images/immutable.png -------------------------------------------------------------------------------- /Ch07/images/flux-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/flux-demo.png -------------------------------------------------------------------------------- /Ch07/images/flux-react.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/flux-react.png -------------------------------------------------------------------------------- /Ch07/images/redux-flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/redux-flow.png -------------------------------------------------------------------------------- /Ch07/images/redux-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/redux-logo.png -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/components/Main/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Main'; 2 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/store/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './configureStore'; 2 | -------------------------------------------------------------------------------- /Ch10/images/client-mvc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch10/images/client-mvc.png -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/components/Counter/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Counter'; -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'HelloWorldApp' 2 | 3 | include ':app' 4 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/ActionButton/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './ActionButton'; -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/InputModal/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './InputModal'; -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/MottoList/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './MottoList'; 2 | -------------------------------------------------------------------------------- /Appendix02/images/demo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/demo-1.png -------------------------------------------------------------------------------- /Appendix02/images/demo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/demo-2.png -------------------------------------------------------------------------------- /Appendix03/images/mocha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix03/images/mocha.png -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/src/components/TodoList/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoList'; -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/components/TodoHeader/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoHeader'; -------------------------------------------------------------------------------- /Ch01/images/html-css-js.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch01/images/html-css-js.png -------------------------------------------------------------------------------- /Ch01/images/react-eco-wp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch01/images/react-eco-wp.gif -------------------------------------------------------------------------------- /Ch02/images/hello-world.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch02/images/hello-world.png -------------------------------------------------------------------------------- /Ch05/images/react-router.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch05/images/react-router.jpg -------------------------------------------------------------------------------- /Ch07/images/react-flux.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/react-flux.jpeg -------------------------------------------------------------------------------- /Ch07/images/redux-folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/redux-folder.png -------------------------------------------------------------------------------- /Ch07/images/redux-store.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/redux-store.png -------------------------------------------------------------------------------- /Ch07/images/using-redux.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/using-redux.jpg -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/containers/TodoListContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoListContainer'; -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/components/HomePage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './HomePage'; 2 | -------------------------------------------------------------------------------- /Appendix01/images/react-es6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix01/images/react-es6.jpg -------------------------------------------------------------------------------- /Appendix02/images/android-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/android-1.png -------------------------------------------------------------------------------- /Appendix02/images/android-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/android-2.png -------------------------------------------------------------------------------- /Appendix02/images/android-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/android-3.png -------------------------------------------------------------------------------- /Appendix02/images/android-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/android-4.png -------------------------------------------------------------------------------- /Appendix02/images/flexbox-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/flexbox-1.png -------------------------------------------------------------------------------- /Appendix02/images/folder-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/folder-1.png -------------------------------------------------------------------------------- /Appendix02/images/folder-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/folder-2.png -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/src/components/TodoHeader/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoHeader'; -------------------------------------------------------------------------------- /Ch02/browserify-example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | ], 6 | "plugins": [] 7 | } -------------------------------------------------------------------------------- /Ch04/images/react-lifecycle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch04/images/react-lifecycle.png -------------------------------------------------------------------------------- /Ch07/images/redux-flowchart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/redux-flowchart.png -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/containers/TodoHeaderContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoHeaderContainer'; -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/components/GithubBox/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './GithubBox'; 2 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/components/ResultPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './ResultPage'; 2 | -------------------------------------------------------------------------------- /Ch10/images/isomorphic-api.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch10/images/isomorphic-api.png -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/Main/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './Main'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/store/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './configureStore'; -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/actions/index.js: -------------------------------------------------------------------------------- 1 | export * from './uiActions'; 2 | export * from './mottoActions'; -------------------------------------------------------------------------------- /Appendix02/images/align-items.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/align-items.png -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/containers/TodoListContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoListContainer'; -------------------------------------------------------------------------------- /Appendix04/graphql-example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | ], 6 | "plugins": [] 7 | } -------------------------------------------------------------------------------- /Ch02/webpack-example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | ], 6 | "plugins": [] 7 | } -------------------------------------------------------------------------------- /Ch05/react-router-example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | ], 6 | "plugins": [] 7 | } -------------------------------------------------------------------------------- /Ch07/images/react-redux-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/react-redux-demo.png -------------------------------------------------------------------------------- /Ch07/react-flux-example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | ], 6 | "plugins": [] 7 | } -------------------------------------------------------------------------------- /Ch07/react-redux-example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | ], 6 | "plugins": [] 7 | } -------------------------------------------------------------------------------- /Ch10/images/client-server-mvc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch10/images/client-server-mvc.png -------------------------------------------------------------------------------- /Ch10/images/open-cook-demo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch10/images/open-cook-demo-1.png -------------------------------------------------------------------------------- /Ch10/images/open-cook-demo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch10/images/open-cook-demo-2.png -------------------------------------------------------------------------------- /Ch10/images/open-cook-demo-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch10/images/open-cook-demo-3.png -------------------------------------------------------------------------------- /Ch10/images/open-cook-demo-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch10/images/open-cook-demo-4.png -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/containers/CounterContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './CounterContainer'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/AppBar/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './AppBar'; -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/containers/InputModalContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './InputModalContainer'; -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/containers/MottoListContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './MottoListContainer'; -------------------------------------------------------------------------------- /Appendix02/images/firebase-init.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/firebase-init.png -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/src/modules/add.js: -------------------------------------------------------------------------------- 1 | const add = (x, y) => ( 2 | x + y 3 | ); 4 | 5 | export default add; -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/containers/TodoHeaderContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './TodoHeaderContainer'; -------------------------------------------------------------------------------- /Appendix04/images/graphql-demo-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix04/images/graphql-demo-1.png -------------------------------------------------------------------------------- /Appendix04/images/graphql-demo-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix04/images/graphql-demo-2.png -------------------------------------------------------------------------------- /Appendix04/images/relay-graphql.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix04/images/relay-graphql.png -------------------------------------------------------------------------------- /Ch07/images/flux-simple-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/flux-simple-diagram.png -------------------------------------------------------------------------------- /Ch07/images/react-flux-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/react-flux-diagram.png -------------------------------------------------------------------------------- /Ch07/images/react-redux-dev-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/react-redux-dev-demo.png -------------------------------------------------------------------------------- /Ch07/images/react-redux-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/react-redux-diagram.png -------------------------------------------------------------------------------- /Ch07/images/using-redux-compare.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch07/images/using-redux-compare.jpg -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/actions/index.js: -------------------------------------------------------------------------------- 1 | export * from './uiActions'; 2 | export * from './githubActions'; 3 | -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | ], 6 | "plugins": [] 7 | } -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/CheckAuth/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './CheckAuth'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/HomePage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './HomePage'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/LoginBox/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './LoginBox'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/LoginPage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './LoginPage'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/RecipeBox/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './RecipeBox'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/ShareBox/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './ShareBox'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/SharePage/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './SharePage'; -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'ReactNativeFirebaseMotto' 2 | 3 | include ':app' 4 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/containers/ActionButtonContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './ActionButtonContainer'; -------------------------------------------------------------------------------- /Appendix02/images/firebase-landing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/firebase-landing.png -------------------------------------------------------------------------------- /Appendix02/images/justify-content.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/justify-content.png -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | ], 6 | "plugins": [] 7 | } -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | ], 6 | "plugins": [] 7 | } -------------------------------------------------------------------------------- /Ch02/images/react-browserify-gulp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch02/images/react-browserify-gulp.png -------------------------------------------------------------------------------- /Ch02/images/webpack-module-bundler.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch02/images/webpack-module-bundler.png -------------------------------------------------------------------------------- /Ch03/todo-examples/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | ], 6 | "plugins": [] 7 | } -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/App/appStyles.js: -------------------------------------------------------------------------------- 1 | export default { 2 | active: { 3 | color: 'red', 4 | }, 5 | }; 6 | -------------------------------------------------------------------------------- /Ch10/images/isomorphic-javascript.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch10/images/isomorphic-javascript.png -------------------------------------------------------------------------------- /Ch10/images/open-cook-demo-folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch10/images/open-cook-demo-folder.png -------------------------------------------------------------------------------- /Appendix02/images/firebase-dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/firebase-dashboard.png -------------------------------------------------------------------------------- /Appendix02/images/firebase-database-0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/firebase-database-0.png -------------------------------------------------------------------------------- /Appendix02/images/firebase-database-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/firebase-database-1.png -------------------------------------------------------------------------------- /Appendix02/images/firebase-database-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/firebase-database-2.png -------------------------------------------------------------------------------- /Appendix02/images/react-native-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/react-native-logo.png -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | ], 6 | "plugins": [] 7 | } -------------------------------------------------------------------------------- /Appendix04/images/relay-architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix04/images/relay-architecture.png -------------------------------------------------------------------------------- /Ch02/images/browserify-folder-pregulp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch02/images/browserify-folder-pregulp.png -------------------------------------------------------------------------------- /Ch02/images/react-webpack-browserify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch02/images/react-webpack-browserify.png -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/containers/HomePageContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './HomePageContainer'; 2 | 3 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/containers/ResultPageContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './ResultPageContainer'; 2 | -------------------------------------------------------------------------------- /Appendix02/images/react-native-init-app.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/react-native-init-app.png -------------------------------------------------------------------------------- /Appendix02/images/react-native-terminal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/react-native-terminal.png -------------------------------------------------------------------------------- /Ch02/images/browserify-folder-possgulp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch02/images/browserify-folder-possgulp.png -------------------------------------------------------------------------------- /Ch10/images/react-server-rendering-demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch10/images/react-server-rendering-demo.png -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/AppBarContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './AppBarContainer'; -------------------------------------------------------------------------------- /Appendix02/images/flexbox-flex-direction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/flexbox-flex-direction.png -------------------------------------------------------------------------------- /Ch03/todo-examples/app/components/TodoHeader/todoHeaderStyles.js: -------------------------------------------------------------------------------- 1 | export default { 2 | todoHeader: { 3 | color: 'red', 4 | }, 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /Ch03/todo-examples/app/components/TodoList/todoListStyles.js: -------------------------------------------------------------------------------- 1 | export default { 2 | todoHeader: { 3 | color: 'red', 4 | }, 5 | }; 6 | 7 | -------------------------------------------------------------------------------- /Ch10/images/react-server-rendering-folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch10/images/react-server-rendering-folder.png -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | ], 6 | "plugins": [] 7 | } -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/HomePageContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './HomePageContainer'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/LoginBoxContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './LoginBoxContainer'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/LoginPageContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './LoginPageContainer'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/RecipeBoxContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './RecipeBoxContainer'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/ShareBoxContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './ShareBoxContainer'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/SharePageContainer/index.js: -------------------------------------------------------------------------------- 1 | export { default } from './SharePageContainer'; -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | "react-native" 6 | ], 7 | "plugins": [] 8 | } -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | HelloWorldApp 3 | 4 | -------------------------------------------------------------------------------- /Appendix02/images/react-native-init-app-reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/images/react-native-init-app-reload.png -------------------------------------------------------------------------------- /Ch05/README.md: -------------------------------------------------------------------------------- 1 | # Ch05 React Router 2 | 3 | 1. [React Router 入门实战教学](react-router-introduction.md) 4 | 5 | ## :door: 任意门 6 | | [回首页](../../../tree/zh-CN/) | -------------------------------------------------------------------------------- /Ch07/react-flux-example/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "no-multiple-empty-lines": [2, {"max": 2, "maxEOF": 2}] 5 | } 6 | } -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/server/index.js: -------------------------------------------------------------------------------- 1 | // use babel-register to precompile ES6 syntax 2 | require('babel-register'); 3 | require('./server'); 4 | -------------------------------------------------------------------------------- /Ch06/README.md: -------------------------------------------------------------------------------- 1 | # Ch06 ImmutableJS 2 | 3 | 1. [ImmutableJS 入门教学](../Ch06/react-immutable-introduction.md) 4 | 5 | ## :door: 任意门 6 | | [回首页](../../../tree/zh-CN/) | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "es2015", 4 | "react", 5 | "babel-preset-stage-1", 6 | ], 7 | "plugins": [] 8 | } -------------------------------------------------------------------------------- /Appendix04/graphql-example/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //require `babel/register` to handle JavaScript code 3 | require('babel/register'); 4 | require('./server.js'); 5 | -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/Home/Home.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Home = () => ( 4 |
Home
5 | ); 6 | 7 | export default Home; 8 | -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/User/User.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const User = () => ( 4 |
User
5 | ); 6 | 7 | export default User; 8 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | ReactNativeFirebaseMotto 3 | 4 | -------------------------------------------------------------------------------- /Ch02/README.md: -------------------------------------------------------------------------------- 1 | # Ch02 React 开发环境设置与 Webpack 入门 2 | 3 | 1. [React 开发环境设置与 Webpack 入门](../Ch02/webpack-dev-enviroment.md) 4 | 5 | ## :door: 任意门 6 | | [回首页](../../../tree/zh-CN/) | -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/About/About.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const About = () => ( 4 |
About
5 | ); 6 | 7 | export default About; 8 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/res/images/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch09/react-router-redux-github-finder/res/images/github.png -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/constants/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const INCREMENT_COUNT = 'INCREMENT_COUNT'; 2 | export const DECREMENT_COUNT = 'DECREMENT_COUNT'; 3 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/actions/index.js: -------------------------------------------------------------------------------- 1 | export * from './userActions'; 2 | export * from './recipeActions'; 3 | export * from './uiActions'; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/server/index.js: -------------------------------------------------------------------------------- 1 | // use babel-register to precompile ES6 syntax 2 | require('babel-register'); 3 | require('./server'); 4 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/server/config/index.js: -------------------------------------------------------------------------------- 1 | export default ({ 2 | "secret": "ilovecooking", 3 | "database": "mongodb://localhost/open_cook" 4 | }); -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/HelloWorldApp/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/.buckconfig: -------------------------------------------------------------------------------- 1 | 2 | [android] 3 | target = Google Inc.:Google APIs:23 4 | 5 | [maven_repositories] 6 | central = https://repo1.maven.org/maven2 7 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/constants/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const CREATE_TODO = 'CREATE_TODO'; 2 | export const DELETE_TODO = 'DELETE_TODO'; 3 | export const CHANGE_TEXT = 'CHANGE_TEXT'; -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/Contacts/Contacts.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Contacts = () => ( 4 |
Contacts
5 | ); 6 | 7 | export default Contacts; 8 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/constants/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const CREATE_TODO = 'CREATE_TODO'; 2 | export const DELETE_TODO = 'DELETE_TODO'; 3 | export const CHANGE_TEXT = 'CHANGE_TEXT'; -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/keystores/debug.keystore.properties: -------------------------------------------------------------------------------- 1 | key.store=debug.keystore 2 | key.alias=androiddebugkey 3 | key.store.password=android 4 | key.alias.password=android 5 | -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/constants/models.js: -------------------------------------------------------------------------------- 1 | import Immutable from 'immutable'; 2 | 3 | // initstate model 4 | export const CounterState = Immutable.Record({ 5 | count: 0, 6 | }); 7 | 8 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/HelloWorldApp/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/HelloWorldApp/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/HelloWorldApp/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/ReactNativeFirebaseMotto/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /Ch01/README.md: -------------------------------------------------------------------------------- 1 | # Ch01 前端工程简介和 React 生态系简介 2 | 3 | 1. [Web 前端工程入门简介](front-end-introduction.md) 4 | 2. [React 生态系入门简介](react-ecosystem-introduction.md) 5 | 6 | ## :door: 任意门 7 | | [回首页](../../../tree/zh-CN/) | -------------------------------------------------------------------------------- /Ch08/README.md: -------------------------------------------------------------------------------- 1 | # Ch08 Container 与 Presentational Components 2 | 3 | 1. [Container 与 Presentational Components 入门](container-presentational-component-.md) 4 | 5 | ## :door: 任意门 6 | | [回首页](../../../tree/zh-CN/) | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/HelloWorldApp/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = 'debug', 3 | store = 'debug.keystore', 4 | properties = 'debug.keystore.properties', 5 | visibility = [ 6 | 'PUBLIC', 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /Appendix04/graphql-example/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 5 | }, 6 | "env" :{ 7 | "es6": true 8 | } 9 | } -------------------------------------------------------------------------------- /Ch05/react-router-example/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 5 | }, 6 | "env" :{ 7 | "browser": true, 8 | } 9 | } -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/keystores/BUCK: -------------------------------------------------------------------------------- 1 | keystore( 2 | name = 'debug', 3 | store = 'debug.keystore', 4 | properties = 'debug.keystore.properties', 5 | visibility = [ 6 | 'PUBLIC', 7 | ], 8 | ) 9 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/constants/config.js: -------------------------------------------------------------------------------- 1 | export const firebaseConfig = { 2 | apiKey: "apiKey", 3 | authDomain: "authDomain", 4 | databaseURL: "databaseURL", 5 | storageBucket: "storageBucket", 6 | }; -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Redux Todo 6 | 7 | 8 |
9 | 10 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/server/public/images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Ch10/react-router-redux-node-isomorphic-open-cook/src/server/public/images/loading.gif -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 5 | }, 6 | "env" :{ 7 | "browser": true, 8 | } 9 | } -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/ReactNativeFirebaseMotto/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/ReactNativeFirebaseMotto/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 5 | }, 6 | "env" :{ 7 | "browser": true, 8 | } 9 | } -------------------------------------------------------------------------------- /Ch03/README.md: -------------------------------------------------------------------------------- 1 | # Ch03 React/JSX/Component 简介 2 | 3 | 1. [ReactJS 与 Component 入门介绍](../Ch03/reactjs-introduction.md) 4 | 2. [JSX 简明入门教学指南](../Ch03/react-jsx-introduction.md) 5 | 6 | ## :door: 任意门 7 | | [回首页](../../../tree/zh-CN/) | -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 5 | }, 6 | "env" :{ 7 | "browser": true, 8 | } 9 | } -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/ReactNativeFirebaseMotto/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/carlleton/reactjs101/HEAD/Appendix02/ReactNativeFirebaseMotto/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test 6 | 7 | 8 |
9 | 10 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Redux Todo 6 | 7 | 8 |
9 | 10 | -------------------------------------------------------------------------------- /Ch07/react-flux-example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TodoFlux 6 | 7 | 8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /Ch09/README.md: -------------------------------------------------------------------------------- 1 | # Ch09 用 React + Router + Redux + ImmutableJS 写一个 Github 查询应用 2 | 3 | 1. [用 React + Router + Redux + ImmutableJS 写一个 Github 查询应用](react-router-redux-github-finder.md) 4 | 5 | ## :door: 任意门 6 | | [回首页](../../../tree/zh-CN/) | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/actions/uiActions.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | import { 3 | TOGGLE_MODAL, 4 | } from '../constants/actionTypes'; 5 | 6 | export const toggleModal = createAction('TOGGLE_MODAL'); 7 | -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import Main from './components/Main'; 4 | 5 | ReactDOM.render( 6 |
, 7 | document.getElementById('app') 8 | ); -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Mocha Test 6 | 7 | 8 |
9 | 10 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 5 | }, 6 | "env" :{ 7 | "browser": true, 8 | } 9 | } -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/constants/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const GET_MOTTOS = 'GET_MOTTOS'; 2 | export const CREATE_MOTTO = 'CREATE_MOTTO'; 3 | export const SET_IN_MOTTO = 'SET_IN_MOTTO'; 4 | export const TOGGLE_MODAL = 'TOGGLE_MODAL'; 5 | -------------------------------------------------------------------------------- /Appendix04/graphql-example/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "1": { 3 | "id": "1", 4 | "name": "Dan" 5 | }, 6 | "2": { 7 | "id": "2", 8 | "name": "Marie" 9 | }, 10 | "3": { 11 | "id": "3", 12 | "name": "Jessie" 13 | } 14 | } -------------------------------------------------------------------------------- /Ch04/README.md: -------------------------------------------------------------------------------- 1 | # Ch04 Props/State 基础与 Component 生命周期 2 | 3 | 1. [Props、State、Refs 与表单处理](props-state-introduction.md) 4 | 2. [React Component 规格与生命周期(Life Cycle)](react-component-life-cycle.md) 5 | 6 | ## :door: 任意门 7 | | [回首页](../../../tree/zh-CN/) | -------------------------------------------------------------------------------- /Ch07/README.md: -------------------------------------------------------------------------------- 1 | # Ch07 Flux/Redux 2 | 3 | 1. [Flux 基础概念与实战入门](react-flux-introduction.md) 4 | 2. [Redux 基础概念](react-redux-introduction.md) 5 | 3. [Redux 实战入门](react-redux-real-world-example.md) 6 | 7 | ## :door: 任意门 8 | | [回首页](../../../tree/zh-CN/) | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 5 | }, 6 | "env" :{ 7 | "browser": true, 8 | "es6": true 9 | } 10 | } -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/NavLink/NavLink.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router'; 3 | 4 | const NavLink = (props) => ( 5 | 6 | ); 7 | 8 | export default NavLink; 9 | -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/.eslint: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 5 | }, 6 | "env" :{ 7 | "browser": true, 8 | "es6": true 9 | } 10 | } -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux-immutable'; 2 | import counterReducers from './counterReducers' 3 | 4 | const rootReducer = combineReducers({ 5 | counterReducers 6 | }); 7 | 8 | export default rootReducer; 9 | -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import Main from './components/Main'; 4 | 5 | const App = () => ( 6 |
7 | ); 8 | 9 | ReactDOM.render(, document.getElementById('app')); 10 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/README.md: -------------------------------------------------------------------------------- 1 | # Redux 2 | 3 | # 延伸阅读 4 | 1. [Question: How to choose between Redux's store and React's state? #1287](https://github.com/reactjs/redux/issues/1287) 5 | 2. [What is the best approach to design state? #1825](https://github.com/reactjs/redux/issues/1825) -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 6 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Redux Todo 6 | 7 | 8 |
9 | 10 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/constants/models.js: -------------------------------------------------------------------------------- 1 | import Immutable from 'immutable'; 2 | 3 | export const TodoState = Immutable.fromJS({ 4 | 'todos': [], 5 | 'todo': { 6 | id: '', 7 | text: '', 8 | updatedAt: '', 9 | completed: false, 10 | } 11 | }); 12 | 13 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/README.md: -------------------------------------------------------------------------------- 1 | # Redux 2 | 3 | # 延伸阅读 4 | 1. [Question: How to choose between Redux's store and React's state? #1287](https://github.com/reactjs/redux/issues/1287) 5 | 2. [What is the best approach to design state? #1825](https://github.com/reactjs/redux/issues/1825) -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/reducers/ui/uiReducers.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions'; 2 | import UiState from '../../constants/models'; 3 | 4 | export default handleActions({ 5 | SHOW: (state, { payload }) => ( 6 | state.set('todos', payload.todo) 7 | ), 8 | }, UiState); -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/constants/models.js: -------------------------------------------------------------------------------- 1 | import Immutable from 'immutable'; 2 | 3 | export const UiState = Immutable.fromJS({ 4 | spinnerVisible: false, 5 | }); 6 | 7 | export const GithubState = Immutable.fromJS({ 8 | userId: '', 9 | data: {}, 10 | }); 11 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/src/components/Main/Main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Main = () => ( 4 |
5 |

Todos

6 |
    7 |
  • Item1
  • 8 |
  • Item2
  • 9 |
10 |
11 | ); 12 | 13 | export default Main; 14 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Redux Todo 6 | 7 | 8 |
9 | 10 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/constants/models.js: -------------------------------------------------------------------------------- 1 | import Immutable from 'immutable'; 2 | 3 | export const TodoState = Immutable.fromJS({ 4 | 'todos': [], 5 | 'todo': { 6 | id: '', 7 | text: '', 8 | updatedAt: '', 9 | completed: false, 10 | } 11 | }); 12 | 13 | -------------------------------------------------------------------------------- /Ch07/react-flux-example/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | TodoFlux 6 | 7 | 8 |
9 | 10 | 11 | -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/api/counter.js: -------------------------------------------------------------------------------- 1 | function getRandomInt(min, max) { 2 | return Math.floor(Math.random() * (max - min)) + min 3 | } 4 | 5 | export function fetchCounter(callback) { 6 | setTimeout(() => { 7 | callback(getRandomInt(1, 100)) 8 | }, 500) 9 | } 10 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | zipStoreBase=GRADLE_USER_HOME 4 | zipStorePath=wrapper/dists 5 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip 6 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/reducers/ui/uiReducers.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions'; 2 | import UiState from '../../constants/models'; 3 | 4 | export default handleActions({ 5 | SHOW: (state, { payload }) => ( 6 | state.set('todos', payload.todo) 7 | ), 8 | }, UiState); -------------------------------------------------------------------------------- /Ch05/react-router-example/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ReactRouter 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux-immutable'; 2 | import ui from './ui/uiReducers'; 3 | import motto from './data/mottoReducers'; 4 | 5 | const rootReducer = combineReducers({ 6 | ui, 7 | motto, 8 | }); 9 | 10 | export default rootReducer; 11 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/containers/ResultPageContainer/ResultPageContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | import ResultPage from '../../components/ResultPage'; 3 | 4 | export default connect( 5 | state => ({ 6 | data: state.getIn(['github', 'data']), 7 | }) 8 | )(ResultPage); 9 | -------------------------------------------------------------------------------- /Ch02/browserify-example/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello React! 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/actions/uiActions.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | import { 3 | SHOW_SPINNER, 4 | HIDE_SPINNER, 5 | } from '../constants/actionTypes'; 6 | 7 | export const showSpinner = createAction(SHOW_SPINNER); 8 | export const hideSpinner = createAction(HIDE_SPINNER); 9 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/MottoList/mottoStyles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet, Dimensions } from 'react-native'; 2 | const { height } = Dimensions.get('window'); 3 | export default StyleSheet.create({ 4 | listView: { 5 | flex: 1, 6 | flexDirection: 'column', 7 | height: height - 105, 8 | }, 9 | }); -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/test/setup.js: -------------------------------------------------------------------------------- 1 | import jsdom from 'jsdom'; 2 | 3 | if (typeof document === 'undefined') { 4 | global.document = jsdom.jsdom(''); 5 | global.window = document.defaultView; 6 | global.navigator = global.window.navigator; 7 | } 8 | -------------------------------------------------------------------------------- /Ch02/browserify-example/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello React! 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "HelloWorldApp", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start" 7 | }, 8 | "dependencies": { 9 | "react": "15.3.1", 10 | "react-native": "0.32.0" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/test/add.test.js: -------------------------------------------------------------------------------- 1 | // test add.js 2 | import add from '../src/modules/add'; 3 | import { expect } from 'chai'; 4 | 5 | // describe is test suite, it is test case 6 | describe('test add function', () => ( 7 | it('1 + 1 = 2', () => ( 8 | expect(add(1, 1)).to.be.equal(2) 9 | )) 10 | )); -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/Repos/Repos.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const Repos = (props) => ( 4 |
5 |

Repos

6 |
{props.params.name}
7 |
8 | ); 9 | 10 | Repos.propTypes = { 11 | params: React.PropTypes.Object, 12 | }; 13 | 14 | export default Repos; 15 | -------------------------------------------------------------------------------- /Ch02/webpack-example/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Setup 6 | 7 | 8 | 9 |
10 | 11 | -------------------------------------------------------------------------------- /Ch03/todo-examples/app/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Setup 6 | 7 | 8 | 9 |
10 | 11 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | GithubFinder 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/constants/models.js: -------------------------------------------------------------------------------- 1 | import Immutable from 'immutable'; 2 | 3 | export const MottoState = Immutable.fromJS({ 4 | mottos: [], 5 | motto: { 6 | id : '', 7 | text: '', 8 | updatedAt: '', 9 | } 10 | }); 11 | 12 | export const UiState = Immutable.fromJS({ 13 | isModalVisible: false, 14 | }); -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux-immutable'; 2 | import ui from './ui/uiReducers';// import routes from './routes'; 3 | import todo from './data/todoReducers';// import routes from './routes'; 4 | 5 | const rootReducer = combineReducers({ 6 | todo, 7 | }); 8 | 9 | export default rootReducer; 10 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import Main from './components/Main'; 5 | import store from './store'; 6 | 7 | ReactDOM.render( 8 | 9 |
10 | , 11 | document.getElementById('app') 12 | ); -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/actions/counterActions.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | import { 3 | INCREMENT_COUNT, 4 | DECREMENT_COUNT, 5 | } from '../constants/actionTypes'; 6 | 7 | export const incrementCount = createAction(INCREMENT_COUNT); 8 | export const decrementCount = createAction(DECREMENT_COUNT); 9 | 10 | 11 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/Main/Main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AppBarContainer from '../../containers/AppBarContainer'; 3 | 4 | const Main = (props) => ( 5 |
6 | 7 |
8 | {props.children} 9 |
10 |
11 | ); 12 | 13 | export default Main; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/SharePageContainer/SharePageContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import SharePage from '../../components/SharePage'; 4 | 5 | export default connect( 6 | (state) => ({ 7 | }), 8 | (dispatch) => ({ 9 | }) 10 | )(SharePage); 11 | 12 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/utils/fetchComponentData.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | 3 | export default function fetchComponentData(token = 'token') { 4 | const promises = [axios.get('http://localhost:3000/api/recipes'), axios.get('http://localhost:3000/api/authenticate?token=' + token)]; 5 | return Promise.all(promises); 6 | } 7 | -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/src/components/Main/Main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TodoHeader from '../TodoHeader'; 3 | import TodoList from '../TodoList'; 4 | 5 | const Main = (props) => ( 6 |
7 |

Todos

8 | 9 | 10 |
11 | ); 12 | 13 | export default Main; -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux-immutable'; 2 | import ui from './ui/uiReducers';// import routes from './routes'; 3 | import todo from './data/todoReducers';// import routes from './routes'; 4 | 5 | const rootReducer = combineReducers({ 6 | todo, 7 | }); 8 | 9 | export default rootReducer; 10 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import Main from './components/Main'; 5 | import store from './store'; 6 | 7 | ReactDOM.render( 8 | 9 |
10 | , 11 | document.getElementById('app') 12 | ); -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/src/components/TodoList/TodoList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | const TodoList = (props) => ( 4 |
5 |
    6 | { 7 | props.todos.map((todo, index) => ( 8 |
  • {todo.text}
  • 9 | )) 10 | } 11 |
12 |
13 | ); 14 | 15 | export default TodoList; -------------------------------------------------------------------------------- /Ch07/react-flux-example/src/actions/todoActions.js: -------------------------------------------------------------------------------- 1 | import AppDispatcher from '../dispatcher/AppDispatcher'; 2 | import { ADD_TODO } from '../constants/actionTypes'; 3 | 4 | export const TodoActions = { 5 | addTodo(text) { 6 | AppDispatcher.handleAction({ 7 | type: ADD_TODO, 8 | payload: { 9 | text, 10 | }, 11 | }); 12 | }, 13 | }; 14 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/constants/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const SHOW_SPINNER = 'SHOW_SPINNER'; 2 | export const HIDE_SPINNER = 'HIDE_SPINNER'; 3 | export const GET_GITHUB_INITIATE = 'GET_GITHUB_INITIATE'; 4 | export const GET_GITHUB_SUCCESS = 'GET_GITHUB_SUCCESS'; 5 | export const GET_GITHUB_FAIL = 'GET_GITHUB_FAIL'; 6 | export const CHAGE_USER_ID = 'CHAGE_USER_ID'; 7 | -------------------------------------------------------------------------------- /Ch10/README.md: -------------------------------------------------------------------------------- 1 | # Ch10 实战教学:用 React + Redux + Node(Isomorphic JavaScript)开发食谱分享网站 2 | 3 | 1. [React Redux Sever Rendering(Isomorphic JavaScript)入门](react-redux-server-rendering-isomorphic-javascript.md) 4 | 2. [用 React + Redux + Node(Isomorphic JavaScript)开发一个食谱分享网站](react-router-redux-node-isomorphic-javascript-open-cook.md) 5 | 6 | ## :door: 任意门 7 | | [回首页](../../../tree/zh-CN/) | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux-immutable'; 2 | import ui from './ui/uiReducers';// import routes from './routes'; 3 | import github from './data/githubReducers';// import routes from './routes'; 4 | 5 | const rootReducer = combineReducers({ 6 | ui, 7 | github, 8 | }); 9 | 10 | export default rootReducer; 11 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/actions/todoActions.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | import { 3 | CREATE_TODO, 4 | DELETE_TODO, 5 | CHANGE_TEXT, 6 | } from '../constants/actionTypes'; 7 | 8 | export const createTodo = createAction('CREATE_TODO'); 9 | export const deleteTodo = createAction('DELETE_TODO'); 10 | export const changeText = createAction('CHANGE_TEXT'); -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/test/promise.test.js: -------------------------------------------------------------------------------- 1 | import fetch from 'node-fetch'; 2 | import { expect } from 'chai'; 3 | 4 | it('asynchronous fetch promise', function() { 5 | return fetch('https://api.github.com/users/torvus') 6 | .then(function(response) { return response.json() }) 7 | .then(function(json) { 8 | expect(json).to.be.an('object'); 9 | }); 10 | }); -------------------------------------------------------------------------------- /Ch03/todo-examples/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Setup 6 | 7 | 8 | 9 |
10 | 11 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/ListItem/listItemStyles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | 3 | export default StyleSheet.create({ 4 | listItemContainer: { 5 | flex: 1, 6 | flexDirection: 'row', 7 | padding: 10, 8 | margin: 5, 9 | }, 10 | listItemText: { 11 | flex: 10, 12 | fontSize: 18, 13 | color: '#212121', 14 | } 15 | }); -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/actions/todoActions.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | import { 3 | CREATE_TODO, 4 | DELETE_TODO, 5 | CHANGE_TEXT, 6 | } from '../constants/actionTypes'; 7 | 8 | export const createTodo = createAction('CREATE_TODO'); 9 | export const deleteTodo = createAction('DELETE_TODO'); 10 | export const changeText = createAction('CHANGE_TEXT'); -------------------------------------------------------------------------------- /Ch02/webpack-example/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React Setup 6 | 7 | 8 | 9 |
10 | 11 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | OpenWeather 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/actions/mottoActions.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | import { 3 | GET_MOTTOS, 4 | CREATE_MOTTO, 5 | SET_IN_MOTTO, 6 | } from '../constants/actionTypes'; 7 | 8 | export const getMottos = createAction('GET_MOTTOS'); 9 | export const createMotto = createAction('CREATE_MOTTO'); 10 | export const setInMotto = createAction('SET_IN_MOTTO'); 11 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/HomePageContainer/HomePageContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import HomePage from '../../components/HomePage'; 4 | 5 | export default connect( 6 | (state) => ({ 7 | recipes: state.getIn(['recipe', 'recipes']), 8 | }), 9 | (dispatch) => ({ 10 | }) 11 | )(HomePage); 12 | 13 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/ToolBar/ToolBar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactNative from 'react-native'; 3 | import styles from './toolBarStyles'; 4 | const { View, Text } = ReactNative; 5 | 6 | const ToolBar = () => ( 7 | 8 | Startup Mottos 9 | 10 | ); 11 | 12 | export default ToolBar; -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/components/Main/Main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import TodoHeaderContainer from '../../containers/TodoHeaderContainer'; 4 | import TodoListContainer from '../../containers/TodoListContainer'; 5 | 6 | const Main = () => ( 7 |
8 | 9 | 10 |
11 | ); 12 | 13 | export default Main; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/LoginPageContainer/LoginPageContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import LoginPage from '../../components/LoginPage'; 4 | 5 | export default connect( 6 | (state) => ({ 7 | spinnerVisible: state.getIn(['ui', 'spinnerVisible']), 8 | }), 9 | (dispatch) => ({ 10 | }) 11 | )(LoginPage); 12 | 13 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/components/Main/Main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import TodoHeaderContainer from '../../containers/TodoHeaderContainer'; 4 | import TodoListContainer from '../../containers/TodoListContainer'; 5 | 6 | const Main = () => ( 7 |
8 | 9 | 10 |
11 | ); 12 | 13 | export default Main; -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }], 5 | "import/no-extraneous-dependencies": [0], 6 | "linebreak-style": ["error", "unix"], 7 | "react/prop-types": ["error", {"ignore": ["children", "route"]}], 8 | "new-cap": [0], 9 | }, 10 | "env" :{ 11 | "browser": true, 12 | } 13 | } -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/reducers/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux-immutable'; 2 | import ui from './ui/uiReducers'; 3 | import recipe from './data/recipeReducers'; 4 | import user from './data/userReducers'; 5 | // import routes from './routes'; 6 | 7 | const rootReducer = combineReducers({ 8 | ui, 9 | recipe, 10 | user, 11 | }); 12 | 13 | export default rootReducer; 14 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/ToolBar/toolBarStyles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | 3 | export default StyleSheet.create({ 4 | toolBarContainer: { 5 | height: 40, 6 | justifyContent: 'center', 7 | alignItems: 'center', 8 | flexDirection: 'column', 9 | backgroundColor: '#ffeb3b', 10 | }, 11 | toolBarText: { 12 | fontSize: 20, 13 | color: '#212121' 14 | } 15 | }); -------------------------------------------------------------------------------- /Appendix04/graphql-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphql-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "kdchang", 10 | "license": "MIT", 11 | "dependencies": { 12 | "express": "^4.14.0", 13 | "express-graphql": "^0.5.4", 14 | "graphql": "^0.7.0" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/test/async.test.js: -------------------------------------------------------------------------------- 1 | import axios from 'axios'; 2 | import { expect } from 'chai'; 3 | 4 | it('asynchronous return an object', function(done){ 5 | axios 6 | .get('https://api.github.com/users/torvus') 7 | .then(function (response) { 8 | expect(response).to.be.an('object'); 9 | done(); 10 | }) 11 | .catch(function (error) { 12 | console.log(error); 13 | }); 14 | }); -------------------------------------------------------------------------------- /Ch02/webpack-example/app/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | class App extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | }; 9 | } 10 | render() { 11 | return ( 12 |
13 |

Hello, World!

14 |
15 | ); 16 | } 17 | } 18 | 19 | ReactDOM.render(, document.getElementById('app')); 20 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/ActionButton/actionButtonStyles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | 3 | export default StyleSheet.create({ 4 | buttonContainer: { 5 | height: 40, 6 | justifyContent: 'center', 7 | alignItems: 'center', 8 | flexDirection: 'column', 9 | backgroundColor: '#66bb6a', 10 | }, 11 | buttonText: { 12 | fontSize: 20, 13 | color: '#e8f5e9' 14 | } 15 | }); -------------------------------------------------------------------------------- /Ch02/browserify-example/app/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | class App extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | this.state = { 8 | }; 9 | } 10 | render() { 11 | return ( 12 |
13 |

Hello, World!

14 |
15 | ); 16 | } 17 | } 18 | 19 | ReactDOM.render(, document.getElementById('app')); 20 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/containers/ActionButtonContainer/ActionButtonContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | import ActionButton from '../../components/ActionButton'; 3 | import { 4 | toggleModal, 5 | } from '../../actions'; 6 | 7 | export default connect( 8 | (state) => ({}), 9 | (dispatch) => ({ 10 | onToggleModal: () => ( 11 | dispatch(toggleModal()) 12 | ) 13 | }) 14 | )(ActionButton); 15 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import createLogger from 'redux-logger'; 3 | import Immutable from 'immutable'; 4 | import rootReducer from '../reducers'; 5 | 6 | const initialState = Immutable.Map(); 7 | 8 | export default createStore( 9 | rootReducer, 10 | initialState, 11 | applyMiddleware(createLogger({ stateTransformer: state => state.toJS() })) 12 | ); 13 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/components/TodoHeader/TodoHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | const TodoHeader = ({ 5 | onChangeText, 6 | onCreateTodo, 7 | todo, 8 | }) => ( 9 |
10 |

TodoHeader

11 | 12 | 13 |
14 | ); 15 | 16 | export default TodoHeader; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/actions/uiActions.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | import WebAPI from '../utils/WebAPI'; 3 | 4 | import { 5 | SHOW_SPINNER, 6 | HIDE_SPINNER, 7 | SET_UI, 8 | } from '../constants/actionTypes'; 9 | 10 | export const showSpinner = createAction('SHOW_SPINNER'); 11 | export const hideSpinner = createAction('HIDE_SPINNER'); 12 | export const setUi = createAction('SET_UI'); -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import createLogger from 'redux-logger'; 3 | import Immutable from 'immutable'; 4 | import rootReducer from '../reducers'; 5 | 6 | const initialState = Immutable.Map(); 7 | 8 | export default createStore( 9 | rootReducer, 10 | initialState, 11 | applyMiddleware(createLogger({ stateTransformer: state => state.toJS() })) 12 | ); 13 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import createLogger from 'redux-logger'; 3 | import Immutable from 'immutable'; 4 | import rootReducer from '../reducers'; 5 | 6 | const initialState = Immutable.Map(); 7 | 8 | export default createStore( 9 | rootReducer, 10 | initialState, 11 | applyMiddleware(createLogger({ stateTransformer: state => state.toJS() })) 12 | ); 13 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/components/TodoHeader/TodoHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | const TodoHeader = ({ 5 | onChangeText, 6 | onCreateTodo, 7 | todo, 8 | }) => ( 9 |
10 |

TodoHeader

11 | 12 | 13 |
14 | ); 15 | 16 | export default TodoHeader; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/HomePage/HomePage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import RecipeBoxContainer from '../../containers/RecipeBoxContainer'; 3 | 4 | const HomePage = ({ 5 | recipes 6 | }) => ( 7 |
8 | { 9 | recipes.map((recipe, index) => ( 10 | 11 | )).toJS() 12 | } 13 |
14 | ); 15 | 16 | export default HomePage; -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/components/ResultPage/ResultPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import GithubBox from '../../components/GithubBox'; 3 | 4 | const ResultPage = props => ( 5 |
6 | 7 |
8 | ); 9 | 10 | ResultPage.propTypes = { 11 | data: React.PropTypes.string, 12 | location: React.PropTypes.Object, 13 | }; 14 | 15 | export default ResultPage; 16 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/components/Main/Main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import AppBar from 'material-ui/AppBar'; 3 | 4 | const Main = props => ( 5 |
6 | 10 |
11 | {props.children} 12 |
13 |
14 | ); 15 | 16 | Main.propTypes = { 17 | children: React.PropTypes.Object, 18 | }; 19 | 20 | export default Main; 21 | -------------------------------------------------------------------------------- /Ch07/react-flux-example/src/dispatcher/AppDispatcher.js: -------------------------------------------------------------------------------- 1 | // Todo app dispatcher with actions responding to both 2 | // view and server actions 3 | import { Dispatcher } from 'flux'; 4 | 5 | class DispatcherClass extends Dispatcher { 6 | 7 | handleAction(action) { 8 | this.dispatch({ 9 | type: action.type, 10 | payload: action.payload, 11 | }); 12 | } 13 | 14 | } 15 | 16 | const AppDispatcher = new DispatcherClass(); 17 | 18 | export default AppDispatcher; 19 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/containers/TodoListContainer/TodoListContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | import TodoList from '../../components/TodoList'; 3 | 4 | import { 5 | deleteTodo, 6 | } from '../../actions'; 7 | 8 | export default connect( 9 | (state) => ({ 10 | todos: state.getIn(['todo', 'todos']) 11 | }), 12 | (dispatch) => ({ 13 | onDeleteTodo: (index) => () => ( 14 | dispatch(deleteTodo({ index })) 15 | ) 16 | }) 17 | )(TodoList); -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/SharePage/SharePage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Grid, Row, Col } from 'react-bootstrap'; 3 | import ShareBoxContainer from '../../containers/ShareBoxContainer'; 4 | 5 | const SharePage = () => ( 6 |
7 | 8 | 9 | 10 | 11 | 12 |
13 | ); 14 | 15 | export default SharePage; -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/test/enzyme/shallowRender.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TestUtils from 'react-addons-test-utils'; 3 | import { expect } from 'chai'; 4 | import { shallow } from 'enzyme'; 5 | import Main from '../../src/components/Main'; 6 | 7 | describe('Enzyme Shallow Rendering', () => { 8 | it('Main title should be Todos', () => { 9 | const main = shallow(
); 10 | expect(main.find('h1').text()).to.equal('Todos'); 11 | }); 12 | }); -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/reducers/ui/uiReducers.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions'; 2 | import { 3 | UiState, 4 | } from '../../constants/models'; 5 | 6 | import { 7 | TOGGLE_MODAL, 8 | } from '../../constants/actionTypes'; 9 | 10 | const uiReducers = handleActions({ 11 | TOGGLE_MODAL: (state) => ( 12 | state.set( 13 | 'isModalVisible', 14 | !state.get('isModalVisible') 15 | ) 16 | ), 17 | }, UiState); 18 | 19 | export default uiReducers; -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/containers/TodoListContainer/TodoListContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | import TodoList from '../../components/TodoList'; 3 | 4 | import { 5 | deleteTodo, 6 | } from '../../actions'; 7 | 8 | export default connect( 9 | (state) => ({ 10 | todos: state.getIn(['todo', 'todos']) 11 | }), 12 | (dispatch) => ({ 13 | onDeleteTodo: (index) => () => ( 14 | dispatch(deleteTodo({ index })) 15 | ) 16 | }) 17 | )(TodoList); -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/reducers/ui/uiReducers.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions'; 2 | import { UiState } from '../../constants/models'; 3 | 4 | const uiReducers = handleActions({ 5 | SHOW_SPINNER: state => ( 6 | state.set( 7 | 'spinnerVisible', 8 | true 9 | ) 10 | ), 11 | HIDE_SPINNER: state => ( 12 | state.set( 13 | 'spinnerVisible', 14 | false 15 | ) 16 | ), 17 | }, UiState); 18 | 19 | export default uiReducers; 20 | -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/README.md: -------------------------------------------------------------------------------- 1 | # Redux Server 端 Rendering 2 | 3 | 要把资料从伺服器端传递到客户端,我们需要: 4 | 5 | 1. 对每个请求建立一个全新的 Redux store 实体 6 | 2. 选择性的 dispatch 一些 action 7 | 3. 把 state 从 store 取出来 8 | 4. 把 state 一起传到客户端 9 | 10 | # 延伸阅读 11 | 1. [Immutable.js usage - Reducers & Server Side Rendering](https://github.com/reactjs/redux/issues/1555) 12 | 2. [Redux Server Rendering](http://redux.js.org/docs/recipes/ServerRendering.html) 13 | 3. [React Router Tutorial](https://github.com/reactjs/react-router-tutorial) -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/server/models/user.js: -------------------------------------------------------------------------------- 1 | // get an instance of mongoose and mongoose.Schema 2 | // const mongoose = require('mongoose'); 3 | // const Schema = mongoose.Schema; 4 | import mongoose, { Schema } from 'mongoose'; 5 | 6 | // set up a mongoose model and pass it using module.exports 7 | export default mongoose.model('User', new Schema({ 8 | id: Number, 9 | username: String, 10 | email: String, 11 | password: String, 12 | admin: Boolean 13 | })); -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/app/src/main/java/com/helloworldapp/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.helloworldapp; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "HelloWorldApp"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import reduxThunk from 'redux-thunk'; 3 | import createLogger from 'redux-logger'; 4 | import Immutable from 'immutable'; 5 | import rootReducer from '../reducers'; 6 | 7 | const initialState = Immutable.Map(); 8 | 9 | export default createStore( 10 | rootReducer, 11 | initialState, 12 | applyMiddleware(reduxThunk, createLogger({ stateTransformer: state => state.toJS() })) 13 | ); 14 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/components/TodoList/TodoList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | const TodoList = ({ 5 | todos, 6 | onDeleteTodo, 7 | }) => ( 8 |
9 |
    10 | { 11 | todos.map((todo, index) => ( 12 |
  • 13 | {todo.get('text')} 14 | 15 |
  • 16 | )).toJS() 17 | } 18 |
19 |
20 | ); 21 | 22 | export default TodoList; -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/components/TodoList/TodoList.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | const TodoList = ({ 5 | todos, 6 | onDeleteTodo, 7 | }) => ( 8 |
9 |
    10 | { 11 | todos.map((todo, index) => ( 12 |
  • 13 | {todo.get('text')} 14 | 15 |
  • 16 | )).toJS() 17 | } 18 |
19 |
20 | ); 21 | 22 | export default TodoList; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/server/models/recipe.js: -------------------------------------------------------------------------------- 1 | // get an instance of mongoose and mongoose.Schema 2 | // const mongoose = require('mongoose'); 3 | // const Schema = mongoose.Schema; 4 | 5 | import mongoose, { Schema } from 'mongoose'; 6 | 7 | // set up a mongoose model and pass it using module.exports 8 | export default mongoose.model('Recipe', new Schema({ 9 | id: String, 10 | name: String, 11 | description: String, 12 | imagePath: String, 13 | steps: Array, 14 | updatedAt: Date, 15 | })); -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/reducers/data/githubReducers.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions'; 2 | import { GithubState } from '../../constants/models'; 3 | 4 | const githubReducers = handleActions({ 5 | GET_GITHUB_SUCCESS: (state, { payload }) => ( 6 | state.merge({ 7 | data: payload.data, 8 | }) 9 | ), 10 | CHAGE_USER_ID: (state, { payload }) => ( 11 | state.merge({ 12 | userId: 13 | payload.userId, 14 | }) 15 | ), 16 | }, GithubState); 17 | 18 | export default githubReducers; 19 | -------------------------------------------------------------------------------- /Ch07/react-flux-example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import TodoHeader from './components/TodoHeader'; 4 | import TodoList from './components/TodoList'; 5 | 6 | class App extends React.Component { 7 | constructor(props) { 8 | super(props); 9 | this.state = {}; 10 | } 11 | render() { 12 | return ( 13 |
14 | 15 | 16 |
17 | ); 18 | } 19 | } 20 | 21 | ReactDOM.render(, document.getElementById('app')); 22 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/app/src/main/java/com/reactnativefirebasemotto/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.reactnativefirebasemotto; 2 | 3 | import com.facebook.react.ReactActivity; 4 | 5 | public class MainActivity extends ReactActivity { 6 | 7 | /** 8 | * Returns the name of the main component registered from JavaScript. 9 | * This is used to schedule rendering of the component. 10 | */ 11 | @Override 12 | protected String getMainComponentName() { 13 | return "ReactNativeFirebaseMotto"; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/ios/HelloWorldApp/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Ch03/todo-examples/app/components/TodoList/TodoList.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | 3 | const TodoList = (props) => ( 4 |
5 |

TodoList

6 |
    7 | { 8 | props.todos.map((todo, index) => ( 9 |
  • 10 |

    {todo.title}

    11 |
  • 12 | )) 13 | } 14 |
15 |
16 | ); 17 | 18 | TodoList.propTypes = { 19 | todos: PropTypes.array, 20 | }; 21 | 22 | TodoList.defaultProps = { 23 | todos: [], 24 | }; 25 | 26 | export default TodoList; 27 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/ActionButton/ActionButton.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactNative from 'react-native'; 3 | import styles from './actionButtonStyles'; 4 | const { View, Text, Modal, TextInput, TouchableHighlight } = ReactNative; 5 | 6 | const ActionButton = (props) => ( 7 | 8 | 9 | Add Motto 10 | 11 | 12 | ); 13 | 14 | export default ActionButton; 15 | -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/test/enzyme/staticRender.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TestUtils from 'react-addons-test-utils'; 3 | import { expect } from 'chai'; 4 | import { render } from 'enzyme'; 5 | import Main from '../../src/components/Main'; 6 | 7 | describe('Enzyme Staic Rendering', () => { 8 | it('Main title should be Todos', () => { 9 | const todos = [{ id: 0, text: 'reading'}, { id: 1, text: 'coding'}]; 10 | const main = render(
); 11 | expect(main.find('h1').text()).to.equal('Todos'); 12 | }); 13 | }); -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/index.android.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | AppRegistry, 10 | Text, 11 | View 12 | } from 'react-native'; 13 | import Main from './src/components/Main'; 14 | 15 | class ReactNativeFirebaseMotto extends Component { 16 | render() { 17 | return ( 18 |
19 | ); 20 | } 21 | } 22 | 23 | AppRegistry.registerComponent('ReactNativeFirebaseMotto', () => ReactNativeFirebaseMotto); 24 | -------------------------------------------------------------------------------- /Ch03/todo-examples/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | 'extends': 'airbnb', 3 | 'parser': 'babel-eslint', 4 | 'plugins': [ 5 | 'react', 6 | ], 7 | "parserOptions": { 8 | "ecmaFeatures": { 9 | "jsx": true, 10 | "modules": true, 11 | } 12 | }, 13 | 'rules': { 14 | 'react/prefer-es6-class': 1, 15 | 'react/jsx-pascal-case': 1, 16 | 'react/jsx-closing-bracket-location': 1, 17 | 'react/wrap-multilines': 1, 18 | 'react/self-closing-comp': 1, 19 | 'react/sort-comp': 1, 20 | 'global-require': 0, 21 | }, 22 | }; 23 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/ios/ReactNativeFirebaseMotto/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | @interface AppDelegate : UIResponder 13 | 14 | @property (nonatomic, strong) UIWindow *window; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/index.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | AppRegistry, 10 | StyleSheet, 11 | Text, 12 | View 13 | } from 'react-native'; 14 | import Main from './src/components/Main'; 15 | 16 | class ReactNativeFirebaseMotto extends Component { 17 | render() { 18 | return ( 19 |
20 | ); 21 | } 22 | } 23 | 24 | AppRegistry.registerComponent('ReactNativeFirebaseMotto', () => ReactNativeFirebaseMotto); 25 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/constants/models.js: -------------------------------------------------------------------------------- 1 | import Immutable from 'immutable'; 2 | 3 | // initstate model 4 | export const UiState = Immutable.fromJS({ 5 | spinnerVisible: false, 6 | isEdit: false, 7 | }); 8 | 9 | export const RecipeState = Immutable.fromJS({ 10 | recipes: [], 11 | recipe: { 12 | id: '', 13 | name: '', 14 | description: '', 15 | imagePath: '', 16 | } 17 | }); 18 | 19 | export const UserState = Immutable.fromJS({ 20 | username: '', 21 | email: '', 22 | password: '', 23 | isAuthorized: false, 24 | }); 25 | -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/test/enzyme/mount.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TestUtils from 'react-addons-test-utils'; 3 | import { expect } from 'chai'; 4 | import { findDOMNode } from 'react-dom'; 5 | import { mount } from 'enzyme'; 6 | import TodoHeader from '../../src/components/TodoHeader'; 7 | 8 | describe('Enzyme Mount', () => { 9 | it('Click Button', () => { 10 | let todoHeaderDOM = mount(); 11 | let button = todoHeaderDOM.find('button').at(0); 12 | button.simulate('click'); 13 | expect(button.prop('disabled')).to.equal(true); 14 | }); 15 | }); -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/containers/CounterContainer/CounterContainer.js: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill'; 2 | import { connect } from 'react-redux'; 3 | import Counter from '../../components/Counter'; 4 | 5 | import { 6 | incrementCount, 7 | decrementCount, 8 | } from '../../actions'; 9 | 10 | export default connect( 11 | (state) => ({ 12 | count: state.get('counterReducers').get('count'), 13 | }), 14 | (dispatch) => ({ 15 | onIncrement: () => ( 16 | dispatch(incrementCount()) 17 | ), 18 | onDecrement: () => ( 19 | dispatch(decrementCount()) 20 | ), 21 | }) 22 | )(Counter); -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/ios/HelloWorldApp/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IJ 26 | # 27 | *.iml 28 | .idea 29 | .gradle 30 | local.properties 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | 37 | # BUCK 38 | buck-out/ 39 | \.buckd/ 40 | android/app/libs 41 | android/keystores/debug.keystore 42 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/ListItem/ListItem.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactNative from 'react-native'; 3 | import styles from './listItemStyles'; 4 | const { View, Text, TouchableHighlight } = ReactNative; 5 | 6 | const ListItem = (props) => { 7 | return ( 8 | 9 | {props.item.get('text')} 10 | 11 | Delete 12 | 13 | 14 | ) 15 | }; 16 | 17 | export default ListItem; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/reducers/data/recipeReducers.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions'; 2 | import { RecipeState } from '../../constants/models'; 3 | 4 | import { 5 | GET_RECIPES, 6 | SET_RECIPE, 7 | } from '../../constants/actionTypes'; 8 | 9 | const recipeReducers = handleActions({ 10 | GET_RECIPES: (state, { payload }) => ( 11 | state.set( 12 | 'recipes', 13 | payload.recipes 14 | ) 15 | ), 16 | SET_RECIPE: (state, { payload }) => ( 17 | state.setIn(payload.keyPath, payload.value) 18 | ), 19 | }, RecipeState); 20 | 21 | export default recipeReducers; 22 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/ios/ReactNativeFirebaseMotto/main.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import 11 | 12 | #import "AppDelegate.h" 13 | 14 | int main(int argc, char * argv[]) { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Ch03/todo-examples/gulpfile.js: -------------------------------------------------------------------------------- 1 | require('babel-core/register'); 2 | 3 | const gulp = require('gulp'); 4 | const eslint = require('gulp-eslint'); 5 | const gulpIf = require('gulp-if'); 6 | 7 | const fix = false; 8 | 9 | function isFixed(file) { 10 | return file.eslint !== null && file.eslint.fixed; 11 | } 12 | 13 | gulp.task('eslint', () => 14 | gulp.src([ 15 | 'app/index.*.js', 16 | 'app/*.js', 17 | 'app/**/*.js', 18 | 'app/**/**/*.js', 19 | 'app/**/**/**/*.js', 20 | ]) 21 | .pipe(eslint({ fix })) 22 | .pipe(eslint.format()) 23 | .pipe(eslint.failAfterError()) 24 | .pipe(gulpIf(isFixed, gulp.dest('src'))) 25 | ); 26 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/containers/TodoHeaderContainer/TodoHeaderContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | import TodoHeader from '../../components/TodoHeader'; 3 | 4 | import { 5 | changeText, 6 | createTodo, 7 | } from '../../actions'; 8 | 9 | export default connect( 10 | (state) => ({ 11 | todo: state.getIn(['todo', 'todo']) 12 | }), 13 | (dispatch) => ({ 14 | onChangeText: (event) => ( 15 | dispatch(changeText({ text: event.target.value })) 16 | ), 17 | onCreateTodo: () => { 18 | dispatch(createTodo()); 19 | dispatch(changeText({ text: '' })); 20 | } 21 | }) 22 | )(TodoHeader); 23 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/.gitignore: -------------------------------------------------------------------------------- 1 | # OSX 2 | # 3 | .DS_Store 4 | 5 | # Xcode 6 | # 7 | build/ 8 | *.pbxuser 9 | !default.pbxuser 10 | *.mode1v3 11 | !default.mode1v3 12 | *.mode2v3 13 | !default.mode2v3 14 | *.perspectivev3 15 | !default.perspectivev3 16 | xcuserdata 17 | *.xccheckout 18 | *.moved-aside 19 | DerivedData 20 | *.hmap 21 | *.ipa 22 | *.xcuserstate 23 | project.xcworkspace 24 | 25 | # Android/IJ 26 | # 27 | *.iml 28 | .idea 29 | .gradle 30 | local.properties 31 | 32 | # node.js 33 | # 34 | node_modules/ 35 | npm-debug.log 36 | 37 | # BUCK 38 | buck-out/ 39 | \.buckd/ 40 | android/app/libs 41 | android/keystores/debug.keystore 42 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/LoginPage/LoginPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Grid, Row, Col, Image } from 'react-bootstrap'; 3 | import LoginBoxContainer from '../../containers/LoginBoxContainer'; 4 | 5 | const LoginPage = ({ 6 | spinnerVisible, 7 | }) => ( 8 |
9 | 10 | 11 | 12 | { spinnerVisible === true ? 13 | : 14 | null 15 | } 16 | 17 | 18 |
19 | ); 20 | 21 | export default LoginPage; -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/containers/TodoHeaderContainer/TodoHeaderContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | import TodoHeader from '../../components/TodoHeader'; 3 | 4 | import { 5 | changeText, 6 | createTodo, 7 | } from '../../actions'; 8 | 9 | export default connect( 10 | (state) => ({ 11 | todo: state.getIn(['todo', 'todo']) 12 | }), 13 | (dispatch) => ({ 14 | onChangeText: (event) => ( 15 | dispatch(changeText({ text: event.target.value })) 16 | ), 17 | onCreateTodo: () => { 18 | dispatch(createTodo()); 19 | dispatch(changeText({ text: '' })); 20 | } 21 | }) 22 | )(TodoHeader); 23 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb", 3 | "rules": { 4 | 'react/prefer-es6-class': 1, 5 | 'react/jsx-pascal-case': 1, 6 | 'react/jsx-closing-bracket-location': 1, 7 | 'react/jsx-filename-extension': [1, { "extensions": [".js", ".jsx"] }], 8 | 'import/extensions': 1, 9 | 'import/no-extraneous-dependencies': 1, 10 | 'react/self-closing-comp': 1, 11 | 'react/jsx-wrap-multilines': 1, 12 | 'react/sort-comp': 1, 13 | 'no-undef': 1, 14 | 'no-unused-vars': 1, 15 | 'no-underscore-dangle': 1, 16 | 'global-require': 0, 17 | 'import/prefer-default-export': 1, 18 | 'new-cap': 1, 19 | } 20 | } -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import promiseMiddleware from 'redux-promise'; 3 | import createLogger from 'redux-logger'; 4 | import Immutable from 'immutable'; 5 | import rootReducer from '../reducers'; 6 | 7 | const initialState = Immutable.Map(); 8 | 9 | export default function configureStore(preloadedState = initialState) { 10 | const store = createStore( 11 | rootReducer, 12 | preloadedState, 13 | applyMiddleware(createLogger({ stateTransformer: state => state.toJS() }, promiseMiddleware)) 14 | ); 15 | 16 | return store; 17 | } 18 | -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/src/components/TodoHeader/TodoHeader.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | class TodoHeader extends React.Component { 4 | constructor(props) { 5 | super(props); 6 | this.toggleButton = this.toggleButton.bind(this); 7 | this.state = { 8 | isActivated: false, 9 | }; 10 | } 11 | toggleButton() { 12 | this.setState({ 13 | isActivated: !this.state.isActivated, 14 | }) 15 | } 16 | render() { 17 | return ( 18 |
19 | 20 |
21 | ); 22 | }; 23 | } 24 | 25 | export default TodoHeader; -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/reducers/counterReducers.js: -------------------------------------------------------------------------------- 1 | import { fromJS } from 'immutable'; 2 | import { handleActions } from 'redux-actions'; 3 | import { CounterState } from '../constants/models'; 4 | 5 | import { 6 | INCREMENT_COUNT, 7 | DECREMENT_COUNT, 8 | } from '../constants/actionTypes'; 9 | 10 | const counterReducers = handleActions({ 11 | INCREMENT_COUNT: (state) => ( 12 | state.set( 13 | 'count', 14 | state.get('count') + 1 15 | ) 16 | ), 17 | DECREMENT_COUNT: (state) => ( 18 | state.set( 19 | 'count', 20 | state.get('count') - 1 21 | ) 22 | ), 23 | }, CounterState); 24 | 25 | export default counterReducers; 26 | -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/test/shallowRender.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TestUtils from 'react-addons-test-utils'; 3 | import { expect } from 'chai'; 4 | import Main from '../src/components/Main'; 5 | 6 | const shallowRender = (Component) => { 7 | const renderer = TestUtils.createRenderer(); 8 | renderer.render(); 9 | return renderer.getRenderOutput(); 10 | } 11 | 12 | describe('Shallow Rendering', () => { 13 | it('Main title should be h1', () => { 14 | const todoItem = shallowRender(Main); 15 | expect(todoItem.props.children[0].type).to.equal('h1'); 16 | expect(todoItem.props.children[0].props.children).to.equal('Todos'); 17 | }); 18 | }); -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/actions/recipeActions.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | import WebAPI from '../utils/WebAPI'; 3 | 4 | import { 5 | GET_RECIPES, 6 | ADD_RECIPE, 7 | UPDATE_RECIPE, 8 | DELETE_RECIPE, 9 | SET_RECIPE, 10 | } from '../constants/actionTypes'; 11 | 12 | export const getRecipes = createAction('GET_RECIPES', WebAPI.getRecipes); 13 | export const addRecipe = createAction('ADD_RECIPE', WebAPI.addRecipe); 14 | export const updateRecipe = createAction('UPDATE_RECIPE', WebAPI.updateRecipe); 15 | export const deleteRecipe = createAction('DELETE_RECIPE', WebAPI.deleteRecipe); 16 | export const setRecipe = createAction('SET_RECIPE'); 17 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/actions/userActions.js: -------------------------------------------------------------------------------- 1 | import { createAction } from 'redux-actions'; 2 | import WebAPI from '../utils/WebAPI'; 3 | 4 | import { 5 | AUTH_START, 6 | AUTH_COMPLETE, 7 | AUTH_ERROR, 8 | START_LOGOUT, 9 | CHECK_AUTH, 10 | SET_USER 11 | } from '../constants/actionTypes'; 12 | 13 | export const authStart = createAction('AUTH_START', WebAPI.login); 14 | export const authComplete = createAction('AUTH_COMPLETE'); 15 | export const authError = createAction('AUTH_ERROR'); 16 | export const startLogout = createAction('START_LOGOUT', WebAPI.logout); 17 | export const checkAuth = createAction('CHECK_AUTH'); 18 | export const setUser = createAction('SET_USER'); 19 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/constants/actionTypes.js: -------------------------------------------------------------------------------- 1 | export const AUTH_START = "AUTH_START"; 2 | export const AUTH_COMPLETE = "AUTH_COMPLETE"; 3 | export const AUTH_ERROR = "AUTH_ERROR"; 4 | export const START_LOGOUT = "START_LOGOUT"; 5 | export const CHECK_AUTH = "CHECK_AUTH"; 6 | export const SET_USER = "SET_USER"; 7 | export const SHOW_SPINNER = "SHOW_SPINNER"; 8 | export const HIDE_SPINNER = "HIDE_SPINNER"; 9 | export const SET_UI = "SET_UI"; 10 | export const GET_RECIPES = 'GET_RECIPES'; 11 | export const SET_RECIPE = 'SET_RECIPE'; 12 | export const ADD_RECIPE = 'ADD_RECIPE'; 13 | export const UPDATE_RECIPE = 'UPDATE_RECIPE'; 14 | export const DELETE_RECIPE = 'DELETE_RECIPE'; 15 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/reducers/ui/uiReducers.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions'; 2 | import { UiState } from '../../constants/models'; 3 | 4 | import { 5 | SHOW_SPINNER, 6 | HIDE_SPINNER, 7 | SET_UI, 8 | } from '../../constants/actionTypes'; 9 | 10 | const uiReducers = handleActions({ 11 | SHOW_SPINNER: (state) => ( 12 | state.set( 13 | 'spinnerVisible', 14 | true 15 | ) 16 | ), 17 | HIDE_SPINNER: (state) => ( 18 | state.set( 19 | 'spinnerVisible', 20 | false 21 | ) 22 | ), 23 | SET_UI: (state, { payload }) => ( 24 | state.set(payload.key, payload.value) 25 | ), 26 | }, UiState); 27 | 28 | export default uiReducers; 29 | -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/client/index.js: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill'; 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import { Provider } from 'react-redux'; 5 | import CounterContainer from '../common/containers/CounterContainer'; 6 | import configureStore from '../common/store/configureStore' 7 | import { fromJS } from 'immutable'; 8 | 9 | // get initial state from server side 10 | const initialState = window.__PRELOADED_STATE__; 11 | 12 | // use initial state to create store and pass to provider 13 | const store = configureStore(fromJS(initialState)) 14 | 15 | ReactDOM.render( 16 | 17 | 18 | , 19 | document.getElementById('app') 20 | ); 21 | 22 | -------------------------------------------------------------------------------- /Ch03/todo-examples/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | 3 | const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({ 4 | template: `${__dirname}/app/index.html`, 5 | filename: 'index.html', 6 | inject: 'body', 7 | }); 8 | 9 | module.exports = { 10 | entry: [ 11 | './app/index.js', 12 | ], 13 | output: { 14 | path: `${__dirname}/dist`, 15 | filename: 'index_bundle.js', 16 | }, 17 | module: { 18 | loaders: [ 19 | { 20 | test: /\.js$/, 21 | exclude: /node_modules/, 22 | loader: 'babel-loader', 23 | }, 24 | ], 25 | }, 26 | devServer: { 27 | inline: true, 28 | port: 8008, 29 | }, 30 | plugins: [HTMLWebpackPluginConfig], 31 | }; 32 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/src/reducers/data/todoReducers.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions'; 2 | import { TodoState } from '../../constants/models'; 3 | 4 | import { 5 | CREATE_TODO, 6 | DELETE_TODO, 7 | CHANGE_TEXT, 8 | } from '../../constants/actionTypes'; 9 | 10 | const todoReducers = handleActions({ 11 | CREATE_TODO: (state) => { 12 | let todos = state.get('todos').push(state.get('todo')); 13 | return state.set('todos', todos) 14 | }, 15 | DELETE_TODO: (state, { payload }) => ( 16 | state.set('todos', state.get('todos').splice(payload.index, 1)) 17 | ), 18 | CHANGE_TEXT: (state, { payload }) => ( 19 | state.merge({ 'todo': payload }) 20 | ) 21 | }, TodoState); 22 | 23 | export default todoReducers; 24 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/src/reducers/data/todoReducers.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions'; 2 | import { TodoState } from '../../constants/models'; 3 | 4 | import { 5 | CREATE_TODO, 6 | DELETE_TODO, 7 | CHANGE_TEXT, 8 | } from '../../constants/actionTypes'; 9 | 10 | const todoReducers = handleActions({ 11 | CREATE_TODO: (state) => { 12 | let todos = state.get('todos').push(state.get('todo')); 13 | return state.set('todos', todos) 14 | }, 15 | DELETE_TODO: (state, { payload }) => ( 16 | state.set('todos', state.get('todos').splice(payload.index, 1)) 17 | ), 18 | CHANGE_TEXT: (state, { payload }) => ( 19 | state.merge({ 'todo': payload }) 20 | ) 21 | }, TodoState); 22 | 23 | export default todoReducers; 24 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/routes/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Route, IndexRoute } from 'react-router'; 3 | import Main from '../components/Main'; 4 | import CheckAuth from '../components/CheckAuth'; 5 | import HomePageContainer from '../containers/HomePageContainer'; 6 | import LoginPageContainer from '../containers/LoginPageContainer'; 7 | import SharePageContainer from '../containers/SharePageContainer'; 8 | 9 | export default ( 10 | 11 | 12 | 13 | 14 | 15 | ); 16 | -------------------------------------------------------------------------------- /Ch03/todo-examples/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | *.pid.lock 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # nyc test coverage 19 | .nyc_output 20 | 21 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 22 | .grunt 23 | 24 | # node-waf configuration 25 | .lock-wscript 26 | 27 | # Compiled binary addons (http://nodejs.org/api/addons.html) 28 | build/Release 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 -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/components/Counter/Counter.js: -------------------------------------------------------------------------------- 1 | import React, { Component, PropTypes } from 'react' 2 | 3 | const Counter = ({ 4 | count, 5 | onIncrement, 6 | onDecrement, 7 | }) => ( 8 |

9 | Clicked: {count} times 10 | {' '} 11 | 14 | {' '} 15 | 18 | {' '} 19 |

20 | ); 21 | 22 | Counter.propTypes = { 23 | count: PropTypes.number.isRequired, 24 | onIncrement: PropTypes.func.isRequired, 25 | onDecrement: PropTypes.func.isRequired 26 | } 27 | 28 | Counter.defaultProps = { 29 | count: 0, 30 | onIncrement: () => {}, 31 | onDecrement: () => {} 32 | } 33 | 34 | export default Counter; -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/test/renderIntoDocument.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TestUtils from 'react-addons-test-utils'; 3 | import { expect } from 'chai'; 4 | import { findDOMNode } from 'react-dom'; 5 | import TodoHeader from '../src/components/TodoHeader'; 6 | 7 | describe('Simulate Event', () => { 8 | it('When click the button, it will be toggle', () => { 9 | const TodoHeaderApp = TestUtils.renderIntoDocument(); 10 | const TodoHeaderDOM = findDOMNode(TodoHeaderApp); 11 | const button = TodoHeaderDOM.querySelector('button'); 12 | TestUtils.Simulate.click(button); 13 | let todoHeaderButtonAfterClick = TodoHeaderDOM.querySelector('button').disabled; 14 | expect(todoHeaderButtonAfterClick).to.equal(true); 15 | }); 16 | }); -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/common/store/configureStore.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import thunk from 'redux-thunk'; 3 | import createLogger from 'redux-logger'; 4 | import rootReducer from '../reducers'; 5 | 6 | export default function configureStore(preloadedState) { 7 | const store = createStore( 8 | rootReducer, 9 | preloadedState, 10 | applyMiddleware(createLogger({ stateTransformer: state => state.toJS() }), thunk) 11 | ) 12 | 13 | if (module.hot) { 14 | // Enable Webpack hot module replacement for reducers 15 | module.hot.accept('../reducers', () => { 16 | const nextRootReducer = require('../reducers').default 17 | store.replaceReducer(nextRootReducer) 18 | }) 19 | } 20 | 21 | return store 22 | } 23 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:1.3.1' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | mavenLocal() 18 | jcenter() 19 | maven { 20 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm 21 | url "$rootDir/../node_modules/react-native/android" 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/webpack.config.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack'; 2 | 3 | module.exports = { 4 | entry: [ 5 | './src/client/index.js', 6 | ], 7 | output: { 8 | path: `${__dirname}/dist`, 9 | filename: 'bundle.js', 10 | publicPath: '/static/' 11 | }, 12 | module: { 13 | preLoaders: [ 14 | { 15 | test: /\.jsx$|\.js$/, 16 | loader: 'eslint-loader', 17 | include: `${__dirname}/app`, 18 | exclude: /bundle\.js$/, 19 | }, 20 | ], 21 | plugins: [ 22 | new webpack.optimize.OccurrenceOrderPlugin(), 23 | new webpack.HotModuleReplacementPlugin() 24 | ], 25 | loaders: [{ 26 | test: /\.js$/, 27 | exclude: /node_modules/, 28 | loader: 'babel-loader', 29 | }], 30 | }, 31 | }; 32 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/reducers/data/mottoReducers.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions'; 2 | import { 3 | MottoState 4 | } from '../../constants/models'; 5 | 6 | import { 7 | GET_MOTTOS, 8 | CREATE_MOTTO, 9 | SET_IN_MOTTO, 10 | } from '../../constants/actionTypes'; 11 | 12 | const mottoReducers = handleActions({ 13 | GET_MOTTOS: (state, { payload }) => ( 14 | state.set( 15 | 'mottos', 16 | payload.mottos 17 | ) 18 | ), 19 | CREATE_MOTTO: (state) => ( 20 | state.set( 21 | 'mottos', 22 | state.get('mottos').push(state.get('motto')) 23 | ) 24 | ), 25 | SET_IN_MOTTO: (state, { payload }) => ( 26 | state.setIn( 27 | payload.path, 28 | payload.value 29 | ) 30 | ) 31 | }, MottoState); 32 | 33 | export default mottoReducers; -------------------------------------------------------------------------------- /Ch02/webpack-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "webpack.config.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "dev": "webpack-dev-server --devtool eval --progress --colors --content-base build" 9 | 10 | }, 11 | "author": "kdchang", 12 | "license": "MIT", 13 | "dependencies": { 14 | "react": "^15.2.1", 15 | "react-dom": "^15.2.1" 16 | }, 17 | "devDependencies": { 18 | "babel-core": "^6.10.4", 19 | "babel-eslint": "^6.0.4", 20 | "babel-loader": "^6.2.4", 21 | "babel-preset-es2015": "^6.9.0", 22 | "babel-preset-react": "^6.11.1", 23 | "html-webpack-plugin": "^2.22.0", 24 | "webpack": "^1.13.1", 25 | "webpack-dev-server": "^1.14.1" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /Ch03/todo-examples/app/components/TodoHeader/TodoHeader.js: -------------------------------------------------------------------------------- 1 | import React, { PropTypes } from 'react'; 2 | import styles from './todoHeaderStyles'; 3 | 4 | const TodoHeader = (props) => ( 5 |
6 |

TodoHeader

7 | 13 | 14 |
15 | ); 16 | 17 | TodoHeader.propTypes = { 18 | todo: PropTypes.object, 19 | onTodoTextChange: PropTypes.func, 20 | onAddTodo: PropTypes.func, 21 | }; 22 | 23 | TodoHeader.defaultProps = { 24 | todo: {}, 25 | onTodoTextChange: () => {}, 26 | onAddTodo: () => {}, 27 | }; 28 | 29 | export default TodoHeader; 30 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/ios/HelloWorldApp/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Ch02/webpack-example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | 3 | const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({ 4 | template: `${__dirname}/app/index.html`, 5 | filename: 'index.html', 6 | inject: 'body', 7 | }); 8 | 9 | module.exports = { 10 | entry: [ 11 | './app/index.js', 12 | ], 13 | output: { 14 | path: `${__dirname}/dist`, 15 | filename: 'index_bundle.js', 16 | }, 17 | module: { 18 | loaders: [ 19 | { 20 | test: /\.js$/, 21 | exclude: /node_modules/, 22 | loader: 'babel-loader', 23 | query: { 24 | presets: ['es2015', 'react'], 25 | }, 26 | }, 27 | ], 28 | }, 29 | devServer: { 30 | inline: true, 31 | port: 8008, 32 | }, 33 | plugins: [HTMLWebpackPluginConfig], 34 | }; 35 | -------------------------------------------------------------------------------- /Ch02/browserify-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browserify-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "kdchang", 10 | "license": "MIT", 11 | "dependencies": { 12 | "gulp": "^3.9.1", 13 | "react": "^15.2.1", 14 | "react-dom": "^15.2.1" 15 | }, 16 | "devDependencies": { 17 | "babel-preset-es2015": "^6.9.0", 18 | "babel-preset-react": "^6.11.1", 19 | "babelify": "^7.3.0", 20 | "browserify": "^13.0.1", 21 | "gulp": "^3.9.1", 22 | "gulp-concat": "^2.6.0", 23 | "gulp-html-replace": "^1.6.1", 24 | "gulp-streamify": "^1.0.2", 25 | "gulp-uglify": "^1.5.4", 26 | "vinyl-source-stream": "^1.1.0", 27 | "watchify": "^3.7.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/client/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import { browserHistory, Router } from 'react-router'; 5 | import { fromJS } from 'immutable'; 6 | import routes from '../common/routes'; 7 | import configureStore from '../common/store/configureStore'; 8 | import { checkAuth } from '../common/actions'; 9 | 10 | // get initial state from server side 11 | const initialState = window.__PRELOADED_STATE__; 12 | 13 | // use initial state to create store and pass to provider 14 | const store = configureStore(fromJS(initialState)); 15 | ReactDOM.render( 16 | 17 | 18 | , 19 | document.getElementById('app') 20 | ); 21 | 22 | 23 | -------------------------------------------------------------------------------- /Ch05/react-router-example/src/components/App/App.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link, IndexLink } from 'react-router'; 3 | import styles from './appStyles'; 4 | import NavLink from '../NavLink'; 5 | 6 | const App = (props) => ( 7 |
8 |

React Router Tutorial

9 |
    10 |
  • Home
  • 11 |
  • About
  • 12 |
  • Repos
  • 13 |
  • User
  • 14 |
  • Contacts
  • 15 |
16 | {props.children} 17 |
18 | ); 19 | 20 | App.propTypes = { 21 | children: React.PropTypes.object, 22 | }; 23 | 24 | export default App; 25 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/ios/ReactNativeFirebaseMotto/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Ch05/react-router-example/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Router, Route, hashHistory, IndexRoute } from 'react-router'; 4 | import App from './components/App'; 5 | import Home from './components/Home'; 6 | import Repos from './components/Repos'; 7 | import About from './components/About'; 8 | import User from './components/User'; 9 | import Contacts from './components/Contacts'; 10 | 11 | ReactDOM.render( 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | , 21 | document.getElementById('app')); 22 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/AppBarContainer/AppBarContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import AppBar from '../../components/AppBar'; 4 | import { browserHistory } from 'react-router'; 5 | 6 | import { 7 | startLogout, 8 | setRecipe, 9 | setUi, 10 | } from '../../actions'; 11 | 12 | export default connect( 13 | (state) => ({ 14 | isAuthorized: state.getIn(['user', 'isAuthorized']), 15 | }), 16 | (dispatch) => ({ 17 | onToShare: () => { 18 | dispatch(setRecipe({ key: 'recipeId', value: '' })); 19 | dispatch(setUi({ key: 'isEdit', value: false })); 20 | window.location.reload(); 21 | browserHistory.push('/share'); 22 | }, 23 | onLogout: () => ( 24 | dispatch(startLogout(dispatch)) 25 | ), 26 | }) 27 | )(AppBar); 28 | 29 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/containers/HomePageContainer/HomePageContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | import HomePage from '../../components/HomePage'; 3 | 4 | import { 5 | getGithub, 6 | changeUserId, 7 | } from '../../actions'; 8 | 9 | export default connect( 10 | state => ({ 11 | userId: state.getIn(['github', 'userId']), 12 | }), 13 | dispatch => ({ 14 | onChangeUserId: event => ( 15 | dispatch(changeUserId(event.target.value)) 16 | ), 17 | onSubmitUserId: userId => () => ( 18 | dispatch(getGithub(userId)) 19 | ), 20 | }), 21 | (stateProps, dispatchProps, ownProps) => { 22 | const { userId } = stateProps; 23 | const { onSubmitUserId } = dispatchProps; 24 | return Object.assign({}, stateProps, dispatchProps, ownProps, { 25 | onSubmitUserId: onSubmitUserId(userId), 26 | }); 27 | } 28 | )(HomePage); 29 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/ios/HelloWorldAppTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/InputModal/inputModelStyles.js: -------------------------------------------------------------------------------- 1 | import { StyleSheet } from 'react-native'; 2 | 3 | export default StyleSheet.create({ 4 | modalHeader: { 5 | flex: 1, 6 | height: 30, 7 | padding: 10, 8 | flexDirection: 'row', 9 | backgroundColor: '#ffc107', 10 | fontSize: 20, 11 | }, 12 | buttonContainer: { 13 | flex: 1, 14 | flexDirection: 'row', 15 | }, 16 | button: { 17 | borderRadius: 5, 18 | 19 | }, 20 | cancelButton: { 21 | flex: 1, 22 | height: 40, 23 | alignItems: 'center', 24 | justifyContent: 'center', 25 | backgroundColor: '#eceff1', 26 | margin: 5, 27 | }, 28 | submitButton: { 29 | flex: 1, 30 | height: 40, 31 | alignItems: 'center', 32 | justifyContent: 'center', 33 | backgroundColor: '#4fc3f7', 34 | margin: 5, 35 | }, 36 | buttonText: { 37 | fontSize: 20, 38 | } 39 | }); -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/actions/githubActions.js: -------------------------------------------------------------------------------- 1 | import 'whatwg-fetch'; 2 | import { 3 | GET_GITHUB_INITIATE, 4 | GET_GITHUB_SUCCESS, 5 | GET_GITHUB_FAIL, 6 | CHAGE_USER_ID, 7 | } from '../constants/actionTypes'; 8 | 9 | import { 10 | showSpinner, 11 | hideSpinner, 12 | } from './uiActions'; 13 | 14 | export const getGithub = (userId = 'torvalds') => ( 15 | (dispatch) => { 16 | dispatch({ type: GET_GITHUB_INITIATE }); 17 | dispatch(showSpinner()); 18 | fetch(`https://api.github.com/users/${userId}`) 19 | .then(response => response.json()) 20 | .then((json) => { 21 | dispatch({ type: GET_GITHUB_SUCCESS, payload: { data: json } }); 22 | dispatch(hideSpinner()); 23 | }) 24 | .catch(() => dispatch({ type: GET_GITHUB_FAIL })); 25 | } 26 | ); 27 | 28 | export const changeUserId = text => ({ type: CHAGE_USER_ID, payload: { userId: text } }); 29 | -------------------------------------------------------------------------------- /Ch05/react-router-example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | 3 | const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({ 4 | template: `${__dirname}/src/index.html`, 5 | filename: 'index.html', 6 | inject: 'body', 7 | }); 8 | 9 | module.exports = { 10 | entry: [ 11 | './src/index.js', 12 | ], 13 | output: { 14 | path: `${__dirname}/dist`, 15 | filename: 'index_bundle.js', 16 | }, 17 | module: { 18 | preLoaders: [ 19 | { 20 | test: /\.jsx$|\.js$/, 21 | loader: 'eslint-loader', 22 | include: `${__dirname}/src`, 23 | exclude: /bundle\.js$/ 24 | } 25 | ], 26 | loaders: [{ 27 | test: /\.js$/, 28 | exclude: /node_modules/, 29 | loader: 'babel-loader', 30 | }], 31 | }, 32 | devServer: { 33 | inline: true, 34 | port: 8008, 35 | }, 36 | plugins: [HTMLWebpackPluginConfig], 37 | }; -------------------------------------------------------------------------------- /Ch07/react-flux-example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | 3 | const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({ 4 | template: `${__dirname}/src/index.html`, 5 | filename: 'index.html', 6 | inject: 'body', 7 | }); 8 | 9 | module.exports = { 10 | entry: [ 11 | './src/index.js', 12 | ], 13 | output: { 14 | path: `${__dirname}/dist`, 15 | filename: 'index_bundle.js', 16 | }, 17 | module: { 18 | preLoaders: [ 19 | { 20 | test: /\.jsx$|\.js$/, 21 | loader: 'eslint-loader', 22 | include: `${__dirname}/src`, 23 | exclude: /bundle\.js$/, 24 | }, 25 | ], 26 | loaders: [{ 27 | test: /\.js$/, 28 | exclude: /node_modules/, 29 | loader: 'babel-loader', 30 | }], 31 | }, 32 | devServer: { 33 | inline: true, 34 | port: 8008, 35 | }, 36 | plugins: [HTMLWebpackPluginConfig], 37 | }; -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/components/HomePage/HomePage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router'; 3 | import RaisedButton from 'material-ui/RaisedButton'; 4 | import TextField from 'material-ui/TextField'; 5 | 6 | const HomePage = ({ 7 | userId, 8 | onSubmitUserId, 9 | onChangeUserId, 10 | }) => ( 11 |
12 | 16 | 22 | 23 | 24 |
25 | ); 26 | 27 | HomePage.propTypes = { 28 | onSubmitUserId: React.PropTypes.func, 29 | onChangeUserId: React.PropTypes.func, 30 | userId: React.PropTypes.string, 31 | }; 32 | 33 | export default HomePage; 34 | -------------------------------------------------------------------------------- /Ch07/react-flux-example/src/components/TodoList/TodoList.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import TodoStore from '../../stores/TodoStore'; 3 | 4 | function getAppState() { 5 | return { 6 | todos: TodoStore.getTodos(), 7 | }; 8 | } 9 | class TodoList extends Component { 10 | constructor(props) { 11 | super(props); 12 | this.onChange = this.onChange.bind(this); 13 | this.state = { 14 | todos: [], 15 | }; 16 | } 17 | componentDidMount() { 18 | TodoStore.addChangeListener(this.onChange); 19 | } 20 | onChange() { 21 | this.setState(getAppState()); 22 | } 23 | render() { 24 | return ( 25 |
26 |
    27 | { 28 | this.state.todos.map((todo, key) => ( 29 |
  • {todo}
  • 30 | )) 31 | } 32 |
33 |
34 | ); 35 | } 36 | } 37 | 38 | export default TodoList; 39 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/ios/ReactNativeFirebaseMottoTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | org.reactjs.native.example.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/test/shallowRenderProps.test.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import TestUtils from 'react-addons-test-utils'; 3 | import { expect } from 'chai'; 4 | import TodoList from '../src/components/TodoList'; 5 | 6 | const shallowRender = (Component, props) => { 7 | const renderer = TestUtils.createRenderer(); 8 | renderer.render(); 9 | return renderer.getRenderOutput(); 10 | } 11 | 12 | describe('Shallow Props Rendering', () => { 13 | it('TodoList props check', () => { 14 | const todos = [{ id: 0, text: 'reading'}, { id: 1, text: 'coding'}]; 15 | const todoList = shallowRender(TodoList, {todos: todos}); 16 | expect(todoList.props.children.type).to.equal('ul'); 17 | expect(todoList.props.children.props.children[0].props.children).to.equal('reading'); 18 | expect(todoList.props.children.props.children[1].props.children).to.equal('coding'); 19 | }); 20 | }); -------------------------------------------------------------------------------- /Ch07/react-redux-example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | 3 | const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({ 4 | template: `${__dirname}/src/index.html`, 5 | filename: 'index.html', 6 | inject: 'body', 7 | }); 8 | 9 | module.exports = { 10 | entry: [ 11 | './src/index.js', 12 | ], 13 | output: { 14 | path: `${__dirname}/dist`, 15 | filename: 'index_bundle.js', 16 | }, 17 | module: { 18 | preLoaders: [ 19 | { 20 | test: /\.jsx$\\.js$/, 21 | loader: 'eslint-loader', 22 | include: `${__dirname}/src`, 23 | exclude: /bundle\.js$/, 24 | }, 25 | ], 26 | loaders: [{ 27 | test: /\.js$/, 28 | exclude: /node_modules/, 29 | loader: 'babel-loader', 30 | }], 31 | }, 32 | devServer: { 33 | inline: true, 34 | port: 8008, 35 | }, 36 | plugins: [HTMLWebpackPluginConfig], 37 | }; 38 | -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/webpack.config.js: -------------------------------------------------------------------------------- 1 | import webpack from 'webpack'; 2 | 3 | module.exports = { 4 | entry: [ 5 | './client/index.js', 6 | ], 7 | output: { 8 | path: `${__dirname}/dist`, 9 | filename: 'bundle.js', 10 | publicPath: '/static/' 11 | }, 12 | module: { 13 | preLoaders: [ 14 | { 15 | test: /\.jsx$|\.js$/, 16 | loader: 'eslint-loader', 17 | include: `${__dirname}/app`, 18 | exclude: /bundle\.js$/, 19 | }, 20 | ], 21 | // 優化並使用 HotModuleReplacement 22 | // plugins: [ 23 | // new webpack.optimize.OccurrenceOrderPlugin(), 24 | // new webpack.HotModuleReplacementPlugin() 25 | // ], 26 | loaders: [{ 27 | test: /\.js$/, 28 | exclude: /node_modules/, 29 | loader: 'babel-loader', 30 | query: { 31 | presets: ['es2015', 'react', 'react-hmre'], 32 | }, 33 | }], 34 | }, 35 | }; 36 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/RecipeBox/RecipeBox.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Grid, Row, Col, Image, Thumbnail, Button } from 'react-bootstrap'; 3 | 4 | const RecipeBox = (props) => { 5 | return( 6 | 7 | 8 |

{props.recipe.get('name')}

9 |

{props.recipe.get('description')}

10 | { 11 | props.isAuthorized === true ? ( 12 |

13 |   14 | 15 |

) 16 | : null 17 | } 18 |
19 | 20 | ); 21 | } 22 | 23 | export default RecipeBox; -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | 3 | const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({ 4 | template: `${__dirname}/src/index.html`, 5 | filename: 'index.html', 6 | inject: 'body', 7 | }); 8 | 9 | module.exports = { 10 | entry: [ 11 | './src/index.js', 12 | ], 13 | output: { 14 | path: `${__dirname}/dist`, 15 | filename: 'index_bundle.js', 16 | }, 17 | module: { 18 | preLoaders: [ 19 | { 20 | test: /\.jsx$|\.js$/, 21 | loader: 'eslint-loader', 22 | include: `${__dirname}/src`, 23 | exclude: /bundle\.js$/ 24 | } 25 | ], 26 | loaders: [{ 27 | test: /\.js$/, 28 | exclude: /node_modules/, 29 | loader: 'babel-loader', 30 | }], 31 | }, 32 | devServer: { 33 | inline: true, 34 | port: 8008, 35 | }, 36 | plugins: [HTMLWebpackPluginConfig], 37 | }; -------------------------------------------------------------------------------- /Ch02/cdn-example/hello.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello React! 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 21 | 22 | -------------------------------------------------------------------------------- /Ch07/react-flux-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-flux-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --colors --inline --content-base ." 8 | }, 9 | "author": "kdchang", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "babel-core": "^6.11.4", 13 | "babel-eslint": "^6.1.2", 14 | "babel-loader": "^6.2.4", 15 | "babel-preset-es2015": "^6.9.0", 16 | "babel-preset-react": "^6.11.1", 17 | "eslint": "^3.2.0", 18 | "eslint-config-airbnb": "^9.0.1", 19 | "eslint-loader": "^1.5.0", 20 | "eslint-plugin-import": "^1.12.0", 21 | "eslint-plugin-jsx-a11y": "^2.0.1", 22 | "eslint-plugin-react": "^5.2.2", 23 | "html-webpack-plugin": "^2.22.0", 24 | "webpack": "^1.13.1", 25 | "webpack-dev-server": "^1.14.1" 26 | }, 27 | "dependencies": { 28 | "flux": "^2.1.1", 29 | "react": "^15.3.0", 30 | "react-dom": "^15.3.0" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Ch07/react-flux-example/src/stores/TodoStore.js: -------------------------------------------------------------------------------- 1 | import AppDispatcher from '../dispatcher/AppDispatcher'; 2 | import { ADD_TODO } from '../constants/actionTypes'; 3 | import { EventEmitter } from 'events'; 4 | 5 | // const CHANGE_EVENT = 'change'; 6 | 7 | const store = { 8 | todos: [], 9 | editing: false, 10 | }; 11 | 12 | class TodoStoreClass extends EventEmitter { 13 | 14 | addChangeListener(callback) { 15 | this.on(ADD_TODO, callback); 16 | } 17 | 18 | removeChangeListener(callback) { 19 | this.removeListener(ADD_TODO, callback); 20 | } 21 | 22 | getTodos() { 23 | return store.todos; 24 | } 25 | } 26 | 27 | const TodoStore = new TodoStoreClass(); 28 | 29 | AppDispatcher.register((action) => { 30 | switch (action.type) { 31 | case ADD_TODO: 32 | store.todos.push(action.payload.text); 33 | TodoStore.emit(ADD_TODO); 34 | break; 35 | default: 36 | return true; 37 | } 38 | return true; 39 | }); 40 | 41 | export default TodoStore; 42 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ReactNativeFirebaseMotto", 3 | "version": "0.0.1", 4 | "private": true, 5 | "scripts": { 6 | "start": "node node_modules/react-native/local-cli/cli.js start" 7 | }, 8 | "dependencies": { 9 | "firebase": "^3.3.0", 10 | "immutable": "^3.8.1", 11 | "react": "15.3.1", 12 | "react-native": "0.32.0", 13 | "react-native-vector-icons": "^2.1.0", 14 | "react-redux": "^4.4.5", 15 | "redux": "^3.5.2", 16 | "redux-actions": "^0.11.0", 17 | "redux-immutable": "^3.0.8", 18 | "uuid": "^2.0.2" 19 | }, 20 | "devDependencies": { 21 | "babel-core": "^6.14.0", 22 | "babel-eslint": "^6.1.2", 23 | "babel-loader": "^6.2.5", 24 | "babel-preset-es2015": "^6.14.0", 25 | "babel-preset-react": "^6.11.1", 26 | "babel-preset-react-native": "^1.9.0", 27 | "babel-preset-stage-1": "^6.13.0", 28 | "eslint-plugin-react-native": "^2.0.0", 29 | "redux-logger": "^2.6.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | 3 | const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({ 4 | template: `${__dirname}/src/index.html`, 5 | filename: 'index.html', 6 | inject: 'body', 7 | }); 8 | 9 | module.exports = { 10 | entry: [ 11 | './src/index.js', 12 | ], 13 | output: { 14 | path: `${__dirname}/dist`, 15 | filename: 'index_bundle.js', 16 | }, 17 | module: { 18 | preLoaders: [ 19 | { 20 | test: /\.jsx$|\.js$/, 21 | loader: 'eslint-loader', 22 | include: `${__dirname}/src`, 23 | exclude: /bundle\.js$/ 24 | } 25 | ], 26 | loaders: [{ 27 | test: /\.js$/, 28 | exclude: /node_modules/, 29 | loader: 'babel-loader', 30 | query: { 31 | presets: ['es2015', 'react'], 32 | }, 33 | }], 34 | }, 35 | devServer: { 36 | inline: true, 37 | port: 8008, 38 | }, 39 | plugins: [HTMLWebpackPluginConfig], 40 | }; -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true 19 | 20 | android.useDeprecatedNdk=true 21 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | 3 | const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({ 4 | template: `${__dirname}/src/index.html`, 5 | filename: 'index.html', 6 | inject: 'body', 7 | }); 8 | 9 | module.exports = { 10 | entry: [ 11 | './src/index.js', 12 | ], 13 | output: { 14 | path: `${__dirname}/dist`, 15 | filename: 'index_bundle.js', 16 | }, 17 | module: { 18 | preLoaders: [ 19 | { 20 | test: /\.jsx$\\.js$/, 21 | loader: 'eslint-loader', 22 | include: `${__dirname}/src`, 23 | exclude: /bundle\.js$/ 24 | } 25 | ], 26 | loaders: [{ 27 | test: /\.js$/, 28 | exclude: /node_modules/, 29 | loader: 'babel-loader', 30 | query: { 31 | presets: ['es2015', 'react'], 32 | }, 33 | }], 34 | }, 35 | devServer: { 36 | inline: true, 37 | port: 8008, 38 | }, 39 | plugins: [HTMLWebpackPluginConfig], 40 | } 41 | -------------------------------------------------------------------------------- /Ch05/react-router-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-router-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "webpack.config.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --colors --inline --content-base ." 8 | }, 9 | "author": "kdchang", 10 | "license": "MIT", 11 | "dependencies": { 12 | "react": "^15.3.1", 13 | "react-dom": "^15.3.1", 14 | "react-router": "^2.7.0" 15 | }, 16 | "devDependencies": { 17 | "babel-core": "^6.13.2", 18 | "babel-eslint": "^6.1.2", 19 | "babel-loader": "^6.2.5", 20 | "babel-preset-es2015": "^6.13.2", 21 | "babel-preset-react": "^6.11.1", 22 | "eslint": "^3.3.1", 23 | "eslint-config-airbnb": "^10.0.1", 24 | "eslint-loader": "^1.5.0", 25 | "eslint-plugin-import": "^1.13.0", 26 | "eslint-plugin-jsx-a11y": "^2.1.0", 27 | "eslint-plugin-react": "^6.1.2", 28 | "html-webpack-plugin": "^2.22.0", 29 | "webpack": "^1.13.2", 30 | "webpack-dev-server": "^1.14.1" 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 2 | 3 | const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({ 4 | template: `${__dirname}/src/index.html`, 5 | filename: 'index.html', 6 | inject: 'body', 7 | }); 8 | 9 | module.exports = { 10 | entry: [ 11 | './src/index.js', 12 | ], 13 | output: { 14 | path: `${__dirname}/dist`, 15 | filename: 'index_bundle.js', 16 | }, 17 | module: { 18 | preLoaders: [ 19 | { 20 | test: /\.jsx$\\.js$/, 21 | loader: 'eslint-loader', 22 | include: `${__dirname}/src`, 23 | exclude: /bundle\.js$/ 24 | } 25 | ], 26 | loaders: [{ 27 | test: /\.js$/, 28 | exclude: /node_modules/, 29 | loader: 'babel-loader', 30 | query: { 31 | presets: ['es2015', 'react'], 32 | }, 33 | }], 34 | }, 35 | devServer: { 36 | inline: true, 37 | port: 8008, 38 | }, 39 | plugins: [HTMLWebpackPluginConfig], 40 | } 41 | -------------------------------------------------------------------------------- /Ch03/todo-examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "enviroment-setup", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "directories": { 7 | "example": "examples" 8 | }, 9 | "scripts": { 10 | "start": "webpack-dev-server --colors --inline --content-base ." 11 | }, 12 | "author": "kdchang", 13 | "license": "MIT", 14 | "devDependencies": { 15 | "babel-core": "^6.10.4", 16 | "babel-eslint": "^6.0.4", 17 | "babel-loader": "^6.2.4", 18 | "babel-preset-es2015": "^6.9.0", 19 | "babel-preset-react": "^6.11.1", 20 | "babel-preset-stage-0": "^6.5.0", 21 | "eslint": "^2.13.1", 22 | "eslint-config-airbnb": "^9.0.1", 23 | "eslint-plugin-import": "^1.8.0", 24 | "eslint-plugin-jsx-a11y": "^1.2.0", 25 | "eslint-plugin-react": "^5.1.1", 26 | "gulp": "^3.9.1", 27 | "gulp-eslint": "^2.0.0", 28 | "gulp-if": "^2.0.1", 29 | "html-webpack-plugin": "^2.22.0", 30 | "webpack": "^1.13.1", 31 | "webpack-dev-server": "^1.14.1" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/app/src/main/java/com/helloworldapp/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.helloworldapp; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | 6 | import com.facebook.react.ReactApplication; 7 | import com.facebook.react.ReactInstanceManager; 8 | import com.facebook.react.ReactNativeHost; 9 | import com.facebook.react.ReactPackage; 10 | import com.facebook.react.shell.MainReactPackage; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class MainApplication extends Application implements ReactApplication { 16 | 17 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 18 | @Override 19 | protected boolean getUseDeveloperSupport() { 20 | return BuildConfig.DEBUG; 21 | } 22 | 23 | @Override 24 | protected List getPackages() { 25 | return Arrays.asList( 26 | new MainReactPackage() 27 | ); 28 | } 29 | }; 30 | 31 | @Override 32 | public ReactNativeHost getReactNativeHost() { 33 | return mReactNativeHost; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import { browserHistory, Router, Route, IndexRoute } from 'react-router'; 5 | import injectTapEventPlugin from 'react-tap-event-plugin'; 6 | import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; 7 | import Main from './components/Main'; 8 | import HomePageContainer from './containers/HomePageContainer'; 9 | import ResultPageContainer from './containers/ResultPageContainer'; 10 | import store from './store'; 11 | 12 | // Needed for onTouchTap 13 | // http://stackoverflow.com/a/34015469/988941 14 | injectTapEventPlugin(); 15 | 16 | ReactDOM.render( 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | , 27 | document.getElementById('app') 28 | ); 29 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/app/src/main/java/com/reactnativefirebasemotto/MainApplication.java: -------------------------------------------------------------------------------- 1 | package com.reactnativefirebasemotto; 2 | 3 | import android.app.Application; 4 | import android.util.Log; 5 | 6 | import com.facebook.react.ReactApplication; 7 | import com.facebook.react.ReactInstanceManager; 8 | import com.facebook.react.ReactNativeHost; 9 | import com.facebook.react.ReactPackage; 10 | import com.facebook.react.shell.MainReactPackage; 11 | 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | public class MainApplication extends Application implements ReactApplication { 16 | 17 | private final ReactNativeHost mReactNativeHost = new ReactNativeHost(this) { 18 | @Override 19 | protected boolean getUseDeveloperSupport() { 20 | return BuildConfig.DEBUG; 21 | } 22 | 23 | @Override 24 | protected List getPackages() { 25 | return Arrays.asList( 26 | new MainReactPackage() 27 | ); 28 | } 29 | }; 30 | 31 | @Override 32 | public ReactNativeHost getReactNativeHost() { 33 | return mReactNativeHost; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/AppBar/AppBar.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { LinkContainer } from 'react-router-bootstrap'; 3 | import { Link } from 'react-router'; 4 | import { Navbar, Nav, NavItem, NavDropdown, MenuItem } from 'react-bootstrap'; 5 | 6 | const AppBar = ({ 7 | isAuthorized, 8 | onToShare, 9 | onLogout, 10 | }) => ( 11 | 12 | 13 | 14 | OpenCook 15 | 16 | 17 | 18 | 19 | { 20 | isAuthorized === false ? 21 | ( 22 | 25 | ) : 26 | ( 27 | 31 | ) 32 | } 33 | 34 | 35 | ); 36 | 37 | export default AppBar; -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/src/components/GithubBox/GithubBox.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Link } from 'react-router'; 3 | import { Card, CardActions, CardHeader, CardText } from 'material-ui/Card'; 4 | import RaisedButton from 'material-ui/RaisedButton'; 5 | import ActionHome from 'material-ui/svg-icons/action/home'; 6 | 7 | const GithubBox = props => ( 8 |
9 | 10 | 15 | 16 | Followers : {props.data.get('followers')} 17 | 18 | 19 | Following : {props.data.get('following')} 20 | 21 | 22 | 23 | } 26 | secondary 27 | /> 28 | 29 | 30 | 31 |
32 | ); 33 | 34 | GithubBox.propTypes = { 35 | data: React.PropTypes.Object, 36 | userId: React.PropTypes.string, 37 | }; 38 | 39 | export default GithubBox; 40 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/reducers/data/userReducers.js: -------------------------------------------------------------------------------- 1 | import { handleActions } from 'redux-actions'; 2 | import { UserState } from '../../constants/models'; 3 | 4 | import { 5 | AUTH_START, 6 | AUTH_COMPLETE, 7 | AUTH_ERROR, 8 | LOGOUT_START, 9 | SET_USER, 10 | } from '../../constants/actionTypes'; 11 | 12 | const userReducers = handleActions({ 13 | AUTH_START: (state) => ( 14 | state.merge({ 15 | isAuthorized: false, 16 | }) 17 | ), 18 | AUTH_COMPLETE: (state) => ( 19 | state.merge({ 20 | email: '', 21 | password: '', 22 | isAuthorized: true, 23 | }) 24 | ), 25 | AUTH_ERROR: (state) => ( 26 | state.merge({ 27 | username: '', 28 | email: '', 29 | password: '', 30 | isAuthorized: false, 31 | }) 32 | ), 33 | START_LOGOUT: (state) => ( 34 | state.merge({ 35 | isAuthorized: false, 36 | }) 37 | ), 38 | CHECK_AUTH: (state) => ( 39 | state.set('isAuthorized', true) 40 | ), 41 | SET_USER: (state, { payload }) => ( 42 | state.set(payload.key, payload.value) 43 | ), 44 | }, UserState); 45 | 46 | export default userReducers; 47 | -------------------------------------------------------------------------------- /Ch07/react-flux-example/src/components/TodoHeader/TodoHeader.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import { TodoActions } from '../../actions/todoActions'; 3 | 4 | class TodoHeader extends Component { 5 | constructor(props) { 6 | super(props); 7 | this.onChange = this.onChange.bind(this); 8 | this.onAdd = this.onAdd.bind(this); 9 | this.state = { 10 | text: '', 11 | editing: false, 12 | }; 13 | } 14 | 15 | onChange(event) { 16 | this.setState({ 17 | text: event.target.value, 18 | }); 19 | } 20 | 21 | onAdd() { 22 | TodoActions.addTodo(this.state.text); 23 | this.setState({ 24 | text: '', 25 | }); 26 | } 27 | 28 | render() { 29 | return ( 30 |
31 |

TodoFlux

32 |
33 | 39 | 44 |
45 |
46 | ); 47 | } 48 | } 49 | 50 | export default TodoHeader; 51 | 52 | -------------------------------------------------------------------------------- /Ch07/react-redux-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-redux-example", 3 | "version": "1.0.0", 4 | "description": "react-redux-example", 5 | "main": "webpack.config.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --colors --inline --content-base ." 8 | }, 9 | "author": "kdchang", 10 | "license": "MIT", 11 | "dependencies": { 12 | "immutable": "^3.8.1", 13 | "react": "^15.3.0", 14 | "react-dom": "^15.3.0", 15 | "react-redux": "^4.4.5", 16 | "redux": "^3.5.2", 17 | "redux-actions": "^0.10.1", 18 | "redux-immutable": "^3.0.7", 19 | "uuid": "^2.0.2" 20 | }, 21 | "devDependencies": { 22 | "babel-core": "^6.13.2", 23 | "babel-eslint": "^6.1.2", 24 | "babel-loader": "^6.2.4", 25 | "babel-preset-es2015": "^6.13.2", 26 | "babel-preset-react": "^6.11.1", 27 | "eslint": "^3.3.1", 28 | "eslint-config-airbnb": "^10.0.1", 29 | "eslint-loader": "^1.5.0", 30 | "eslint-plugin-import": "^1.13.0", 31 | "eslint-plugin-jsx-a11y": "^2.1.0", 32 | "eslint-plugin-react": "^6.1.1", 33 | "html-webpack-plugin": "^2.22.0", 34 | "redux-logger": "^2.6.1", 35 | "webpack": "^1.13.1", 36 | "webpack-dev-server": "^1.14.1" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /Appendix03/react-mocha-test-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-mocha-test-example", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "webpack.config.js", 6 | "directories": { 7 | "test": "test" 8 | }, 9 | "scripts": { 10 | "start": "webpack-dev-server --colors --inline --content-base .", 11 | "test": "mocha -t 5000 --compilers js:babel-core/register" 12 | }, 13 | "author": "kdchang", 14 | "license": "MIT", 15 | "devDependencies": { 16 | "babel-core": "^6.14.0", 17 | "babel-eslint": "^6.1.2", 18 | "babel-loader": "^6.2.5", 19 | "babel-preset-es2015": "^6.14.0", 20 | "babel-preset-react": "^6.11.1", 21 | "chai": "^3.5.0", 22 | "eslint": "^3.4.0", 23 | "eslint-config-airbnb": "^10.0.1", 24 | "eslint-loader": "^1.5.0", 25 | "eslint-plugin-import": "^1.14.0", 26 | "eslint-plugin-jsx-a11y": "^2.2.1", 27 | "eslint-plugin-react": "^6.2.0", 28 | "html-webpack-plugin": "^2.22.0", 29 | "mocha": "^3.0.2", 30 | "webpack": "^1.13.2", 31 | "webpack-dev-server": "^1.15.1" 32 | }, 33 | "dependencies": { 34 | "axios": "^0.14.0", 35 | "node-fetch": "^1.6.0", 36 | "react": "^15.3.1", 37 | "react-dom": "^15.3.1" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/Main/Main.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactNative from 'react-native'; 3 | import { Provider } from 'react-redux'; 4 | import ToolBar from '../ToolBar'; 5 | import MottoListContainer from '../../containers/MottoListContainer'; 6 | import ActionButtonContainer from '../../containers/ActionButtonContainer'; 7 | import InputModalContainer from '../../containers/InputModalContainer'; 8 | import ListItem from '../ListItem'; 9 | import * as firebase from 'firebase'; 10 | import { firebaseConfig } from '../../constants/config'; 11 | import store from '../../store'; 12 | const { View, Text } = ReactNative; 13 | 14 | // Initialize Firebase 15 | const firebaseApp = firebase.initializeApp(firebaseConfig); 16 | // Create a reference with .ref() instead of new Firebase(url) 17 | const rootRef = firebaseApp.database().ref(); 18 | const itemsRef = rootRef.child('items'); 19 | 20 | const Main = () => ( 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | ); 30 | 31 | export default Main; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/LoginBoxContainer/LoginBoxContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import LoginBox from '../../components/LoginBox'; 4 | 5 | import { 6 | authStart, 7 | showSpinner, 8 | setUser, 9 | } from '../../actions'; 10 | 11 | export default connect( 12 | (state) => ({ 13 | email: state.getIn(['user', 'email']), 14 | password: state.getIn(['user', 'password']), 15 | }), 16 | (dispatch) => ({ 17 | onChangeEmailInput: (event) => ( 18 | dispatch(setUser({ key: 'email', value: event.target.value })) 19 | ), 20 | onChangePasswordInput: (event) => ( 21 | dispatch(setUser({ key: 'password', value: event.target.value })) 22 | ), 23 | onLoginSubmit: (email, password) => () => { 24 | dispatch(authStart(dispatch, email, password)); 25 | dispatch(showSpinner()); 26 | }, 27 | }), 28 | (stateProps, dispatchProps, ownProps) => { 29 | const { email, password } = stateProps; 30 | const { onLoginSubmit } = dispatchProps; 31 | return Object.assign({}, stateProps, dispatchProps, ownProps, { 32 | onLoginSubmit: onLoginSubmit(email, password), 33 | }); 34 | } 35 | )(LoginBox); 36 | 37 | -------------------------------------------------------------------------------- /Appendix03/react-addons-test-utils-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-redux-example", 3 | "version": "1.0.0", 4 | "description": "react-redux-example", 5 | "main": "webpack.config.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --colors --inline --content-base .", 8 | "test": "mocha --compilers js:babel-core/register --require ./test/setup.js --recursive" 9 | }, 10 | "author": "kdchang", 11 | "license": "MIT", 12 | "dependencies": { 13 | "react": "^15.3.0", 14 | "react-dom": "^15.3.0" 15 | }, 16 | "devDependencies": { 17 | "babel-core": "^6.13.2", 18 | "babel-eslint": "^6.1.2", 19 | "babel-loader": "^6.2.4", 20 | "babel-preset-es2015": "^6.14.0", 21 | "babel-preset-react": "^6.11.1", 22 | "chai": "^3.5.0", 23 | "enzyme": "^2.4.1", 24 | "eslint": "^3.3.1", 25 | "eslint-config-airbnb": "^10.0.1", 26 | "eslint-loader": "^1.5.0", 27 | "eslint-plugin-import": "^1.13.0", 28 | "eslint-plugin-jsx-a11y": "^2.1.0", 29 | "eslint-plugin-react": "^6.1.1", 30 | "html-webpack-plugin": "^2.22.0", 31 | "jsdom": "^9.5.0", 32 | "mocha": "^3.0.2", 33 | "react-addons-test-utils": "^15.3.1", 34 | "webpack": "^1.13.1", 35 | "webpack-dev-server": "^1.14.1" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 19 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/containers/MottoListContainer/MottoListContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | import MottoList from '../../components/MottoList'; 3 | import Immutable from 'immutable'; 4 | import uuid from 'uuid'; 5 | 6 | import { 7 | createMotto, 8 | getMottos, 9 | changeMottoTitle, 10 | } from '../../actions'; 11 | 12 | export default connect( 13 | (state) => ({ 14 | mottos: state.getIn(['motto', 'mottos']), 15 | }), 16 | (dispatch) => ({ 17 | onCreateMotto: () => ( 18 | dispatch(createMotto()) 19 | ), 20 | onGetMottos: (mottos) => ( 21 | dispatch(getMottos({ mottos })) 22 | ), 23 | onChangeMottoTitle: (title) => ( 24 | dispatch(changeMottoTitle({ value: title })) 25 | ), 26 | onDeleteMotto: (mottos) => (id, itemsRef) => () => { 27 | mottos.forEach((value, key) => { 28 | if(value.get('id') === id) { 29 | itemsRef.child(key).remove(); 30 | } 31 | }); 32 | } 33 | }), 34 | (stateToProps, dispatchToProps, ownProps) => { 35 | const { mottos } = stateToProps; 36 | const { onDeleteMotto } = dispatchToProps; 37 | return Object.assign({}, stateToProps, dispatchToProps, ownProps, { 38 | onDeleteMotto: onDeleteMotto(mottos), 39 | }); 40 | } 41 | )(MottoList); -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/LoginBox/LoginBox.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Form, FormGroup, Button, FormControl, ControlLabel } from 'react-bootstrap'; 3 | 4 | const LoginBox = ({ 5 | email, 6 | password, 7 | onChangeEmailInput, 8 | onChangePasswordInput, 9 | onLoginSubmit 10 | }) => ( 11 |
12 |
13 | 16 | 請輸入您的 Email 17 | 22 | 23 | 24 | 27 | 請輸入您的密碼 28 | 33 | 34 | 35 | 43 |
44 |
45 | ); 46 | 47 | export default LoginBox; -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/index.ios.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | AppRegistry, 10 | StyleSheet, 11 | Text, 12 | View 13 | } from 'react-native'; 14 | 15 | class HelloWorldApp extends Component { 16 | render() { 17 | return ( 18 | 19 | 20 | Welcome to React Native! 21 | 22 | 23 | To get started, edit index.ios.js 24 | 25 | 26 | Press Cmd+R to reload,{'\n'} 27 | Cmd+D or shake for dev menu 28 | 29 | 30 | ); 31 | } 32 | } 33 | 34 | const styles = StyleSheet.create({ 35 | container: { 36 | flex: 1, 37 | justifyContent: 'center', 38 | alignItems: 'center', 39 | backgroundColor: '#F5FCFF', 40 | }, 41 | welcome: { 42 | fontSize: 20, 43 | textAlign: 'center', 44 | margin: 10, 45 | }, 46 | instructions: { 47 | textAlign: 'center', 48 | color: '#333333', 49 | marginBottom: 5, 50 | }, 51 | }); 52 | 53 | AppRegistry.registerComponent('HelloWorldApp', () => HelloWorldApp); 54 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/index.android.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Sample React Native App 3 | * https://github.com/facebook/react-native 4 | * @flow 5 | */ 6 | 7 | import React, { Component } from 'react'; 8 | import { 9 | AppRegistry, 10 | StyleSheet, 11 | Text, 12 | View 13 | } from 'react-native'; 14 | 15 | class HelloWorldApp extends Component { 16 | render() { 17 | return ( 18 | 19 | 20 | Welcome to React Native Rock!!!! 21 | 22 | 23 | To get started, edit index.android.js 24 | 25 | 26 | Double tap R on your keyboard to reload,{'\n'} 27 | Shake or press menu button for dev menu 28 | 29 | 30 | ); 31 | } 32 | } 33 | 34 | const styles = StyleSheet.create({ 35 | container: { 36 | flex: 1, 37 | justifyContent: 'center', 38 | alignItems: 'center', 39 | backgroundColor: '#F5FCFF', 40 | }, 41 | welcome: { 42 | fontSize: 20, 43 | textAlign: 'center', 44 | margin: 10, 45 | }, 46 | instructions: { 47 | textAlign: 'center', 48 | color: '#333333', 49 | marginBottom: 5, 50 | }, 51 | }); 52 | 53 | AppRegistry.registerComponent('HelloWorldApp', () => HelloWorldApp); 54 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/containers/InputModalContainer/InputModalContainer.js: -------------------------------------------------------------------------------- 1 | import { connect } from 'react-redux'; 2 | import InputModal from '../../components/InputModal'; 3 | import Immutable from 'immutable'; 4 | 5 | import { 6 | toggleModal, 7 | setInMotto, 8 | createMotto, 9 | } from '../../actions'; 10 | import uuid from 'uuid'; 11 | 12 | export default connect( 13 | (state) => ({ 14 | isModalVisible: state.getIn(['ui', 'isModalVisible']), 15 | motto: state.getIn(['motto', 'motto']), 16 | }), 17 | (dispatch) => ({ 18 | onToggleModal: () => ( 19 | dispatch(toggleModal()) 20 | ), 21 | onChangeMottoText: (text) => ( 22 | dispatch(setInMotto({ path: ['motto', 'text'], value: text })) 23 | ), 24 | onCreateMotto: (motto) => (itemsRef) => () => { 25 | itemsRef.push({ id: uuid.v4(), text: motto.get('text'), updatedAt: Date.now() }); 26 | dispatch(setInMotto({ path: ['motto'], value: Immutable.fromJS({ id: '', text: '', updatedAt: '' })})); 27 | dispatch(toggleModal()); 28 | } 29 | }), 30 | (stateToProps, dispatchToProps, ownProps) => { 31 | const { motto } = stateToProps; 32 | const { onCreateMotto } = dispatchToProps; 33 | return Object.assign({}, stateToProps, dispatchToProps, ownProps, { 34 | onCreateMotto: onCreateMotto(motto), 35 | }); 36 | }, 37 | )(InputModal); 38 | -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/components/CheckAuth/CheckAuth.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { withRouter } from 'react-router'; 4 | 5 | // High Order Component 6 | export default function requireAuthentication(Component, type) { 7 | class AuthenticatedComponent extends React.Component { 8 | componentWillMount() { 9 | this.checkAuth(); 10 | } 11 | componentWillReceiveProps(nextProps) { 12 | this.checkAuth(); 13 | } 14 | checkAuth() { 15 | if(type === 'auth') { 16 | if (!this.props.isAuthorized) { 17 | this.props.router.push('/'); 18 | } 19 | } else { 20 | if (this.props.isAuthorized) { 21 | this.props.router.push('/'); 22 | } 23 | } 24 | } 25 | render() { 26 | return ( 27 |
28 | { 29 | (type === 'auth') ? 30 | this.props.isAuthorized === true ? : null 31 | : this.props.isAuthorized === false ? : null 32 | } 33 |
34 | ) 35 | } 36 | }; 37 | 38 | const mapStateToProps = (state) => ({ 39 | isAuthorized: state.getIn(['user', 'isAuthorized']), 40 | }); 41 | 42 | return connect(mapStateToProps)(withRouter(AuthenticatedComponent)); 43 | } 44 | 45 | -------------------------------------------------------------------------------- /Ch09/react-router-redux-github-finder/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-router-redux-github-finder", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "webpack.config.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --colors --inline --content-base ." 8 | }, 9 | "author": "kdchang", 10 | "license": "MIT", 11 | "dependencies": { 12 | "immutable": "^3.8.1", 13 | "material-ui": "^0.15.4", 14 | "react": "^15.3.0", 15 | "react-dom": "^15.3.0", 16 | "react-redux": "^4.4.5", 17 | "react-router": "^2.6.1", 18 | "react-tap-event-plugin": "^1.0.0", 19 | "redux": "^3.5.2", 20 | "redux-actions": "^0.10.1", 21 | "redux-immutable": "^3.0.7", 22 | "redux-thunk": "^2.1.0", 23 | "whatwg-fetch": "^1.0.0" 24 | }, 25 | "devDependencies": { 26 | "babel-core": "^6.13.2", 27 | "babel-eslint": "^6.1.2", 28 | "babel-loader": "^6.2.4", 29 | "babel-preset-es2015": "^6.13.2", 30 | "babel-preset-react": "^6.11.1", 31 | "babel-preset-stage-1": "^6.13.0", 32 | "eslint": "^3.3.0", 33 | "eslint-config-airbnb": "^10.0.1", 34 | "eslint-loader": "^1.5.0", 35 | "eslint-plugin-import": "^1.13.0", 36 | "eslint-plugin-jsx-a11y": "^2.1.0", 37 | "eslint-plugin-react": "^6.1.0", 38 | "html-webpack-plugin": "^2.22.0", 39 | "redux-logger": "^2.6.1", 40 | "webpack": "^1.13.1", 41 | "webpack-dev-server": "^1.14.1" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Appendix03/react-redux-test-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-redux-example", 3 | "version": "1.0.0", 4 | "description": "react-redux-example", 5 | "main": "webpack.config.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --colors --inline --content-base .", 8 | "test": "mocha --compilers js:babel-core/register" 9 | }, 10 | "author": "kdchang", 11 | "license": "MIT", 12 | "dependencies": { 13 | "immutable": "^3.8.1", 14 | "react": "^15.3.0", 15 | "react-dom": "^15.3.0", 16 | "react-redux": "^4.4.5", 17 | "redux": "^3.5.2", 18 | "redux-actions": "^0.10.1", 19 | "redux-immutable": "^3.0.7", 20 | "uuid": "^2.0.2" 21 | }, 22 | "devDependencies": { 23 | "babel-core": "^6.13.2", 24 | "babel-eslint": "^6.1.2", 25 | "babel-loader": "^6.2.4", 26 | "babel-preset-es2015": "^6.14.0", 27 | "babel-preset-react": "^6.11.1", 28 | "chai": "^3.5.0", 29 | "enzyme": "^2.4.1", 30 | "eslint": "^3.3.1", 31 | "eslint-config-airbnb": "^10.0.1", 32 | "eslint-loader": "^1.5.0", 33 | "eslint-plugin-import": "^1.13.0", 34 | "eslint-plugin-jsx-a11y": "^2.1.0", 35 | "eslint-plugin-react": "^6.1.1", 36 | "html-webpack-plugin": "^2.22.0", 37 | "jsdom": "^9.5.0", 38 | "mocha": "^3.0.2", 39 | "react-addons-test-utils": "^15.3.1", 40 | "redux-logger": "^2.6.1", 41 | "redux-mock-store": "^1.2.0", 42 | "webpack": "^1.13.1", 43 | "webpack-dev-server": "^1.14.1" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Ch03/todo-examples/app/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import TodoHeader from './components/TodoHeader'; 4 | import TodoList from './components/TodoList'; 5 | 6 | class App extends React.Component { 7 | constructor(props) { 8 | super(props); 9 | this.handleTodoTextChange = this.handleTodoTextChange.bind(this); 10 | this.handleAddTodo = this.handleAddTodo.bind(this); 11 | this.state = { 12 | todos: [], 13 | todo: { 14 | id: '', 15 | title: '', 16 | updatedAt: '', 17 | }, 18 | }; 19 | } 20 | handleTodoTextChange(e) { 21 | this.setState({ 22 | todo: { 23 | title: e.target.value, 24 | }, 25 | }); 26 | console.log(e.target.value); 27 | } 28 | handleAddTodo() { 29 | this.state.todos.push(this.state.todo); 30 | this.setState({ 31 | todos: this.state.todos, 32 | todo: { 33 | id: '', 34 | title: '', 35 | updatedAt: '', 36 | }, 37 | }); 38 | console.log(this.state.todo); 39 | } 40 | render() { 41 | return ( 42 |
43 | 48 | 51 |
52 | ); 53 | } 54 | } 55 | 56 | ReactDOM.render(, document.getElementById('app')); 57 | -------------------------------------------------------------------------------- /Appendix02/ReactNativeFirebaseMotto/src/components/InputModal/InputModal.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactNative from 'react-native'; 3 | import styles from './inputModelStyles'; 4 | const { View, Text, Modal, TextInput, TouchableHighlight } = ReactNative; 5 | const InputModal = (props) => ( 6 | 7 | 13 | 14 | 15 | Please Keyin your Motto! 16 | 19 | 20 | 24 | 27 | Cancel 28 | 29 | 30 | 34 | 37 | Submit 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | ); 46 | 47 | export default InputModal; -------------------------------------------------------------------------------- /Ch10/react-router-redux-node-isomorphic-open-cook/src/common/containers/RecipeBoxContainer/RecipeBoxContainer.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { connect } from 'react-redux'; 3 | import RecipeBox from '../../components/RecipeBox'; 4 | import { browserHistory } from 'react-router'; 5 | 6 | import { 7 | deleteRecipe, 8 | setRecipe, 9 | setUi 10 | } from '../../actions'; 11 | 12 | export default connect( 13 | (state) => ({ 14 | isAuthorized: state.getIn(['user', 'isAuthorized']), 15 | recipes: state.getIn(['recipe', 'recipes']), 16 | }), 17 | (dispatch) => ({ 18 | onDeleteRecipe: (recipeId) => () => ( 19 | dispatch(deleteRecipe(dispatch, recipeId)) 20 | ), 21 | onUpadateRecipe: (recipes) => (recipeId) => () => { 22 | const recipeIndex = recipes.findIndex((_recipe) => (_recipe.get('_id') === recipeId)); 23 | const recipe = recipeIndex !== -1 ? recipes.get(recipeIndex) : undefined; 24 | dispatch(setRecipe({ keyPath: ['recipe'], value: recipe })); 25 | dispatch(setRecipe({ keyPath: ['recipe', 'id'], value: recipeId })); 26 | dispatch(setUi({ key: 'isEdit', value: true })); 27 | browserHistory.push('/share?recipeId=' + recipeId); 28 | }, 29 | }), 30 | (stateProps, dispatchProps, ownProps) => { 31 | const { recipes } = stateProps; 32 | const { onUpadateRecipe } = dispatchProps; 33 | return Object.assign({}, stateProps, dispatchProps, ownProps, { 34 | onUpadateRecipe: onUpadateRecipe(recipes), 35 | }); 36 | } 37 | )(RecipeBox); 38 | 39 | -------------------------------------------------------------------------------- /Ch10/react-redux-server-rendering/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-redux-server-rendering", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node server/index.js" 8 | }, 9 | "author": "kdchang", 10 | "license": "MIT", 11 | "dependencies": { 12 | "babel-polyfill": "^6.13.0", 13 | "babel-register": "^6.11.6", 14 | "body-parser": "^1.15.2", 15 | "express": "^4.14.0", 16 | "immutable": "^3.8.1", 17 | "morgan": "^1.7.0", 18 | "qs": "^6.2.1", 19 | "react": "^15.3.0", 20 | "react-dom": "^15.3.0", 21 | "react-redux": "^4.4.5", 22 | "react-router": "^2.6.1", 23 | "redux": "^3.5.2", 24 | "redux-actions": "^0.10.1", 25 | "redux-immutable": "^3.0.6", 26 | "redux-logger": "^2.6.1", 27 | "redux-thunk": "^2.1.0" 28 | }, 29 | "devDependencies": { 30 | "babel-core": "^6.13.2", 31 | "babel-eslint": "^6.1.2", 32 | "babel-loader": "^6.2.4", 33 | "babel-preset-es2015": "^6.13.2", 34 | "babel-preset-react": "^6.11.1", 35 | "babel-preset-react-hmre": "^1.1.1", 36 | "babel-runtime": "^6.11.6", 37 | "eslint": "^3.2.2", 38 | "eslint-config-airbnb": "^10.0.0", 39 | "eslint-loader": "^1.5.0", 40 | "eslint-plugin-import": "^1.12.0", 41 | "eslint-plugin-jsx-a11y": "^2.0.1", 42 | "eslint-plugin-react": "^6.0.0", 43 | "webpack": "^1.13.1", 44 | "webpack-dev-middleware": "^1.6.1", 45 | "webpack-dev-server": "^1.14.1", 46 | "webpack-hot-middleware": "^2.12.2" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Appendix02/HelloWorldApp/ios/HelloWorldApp/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2015-present, Facebook, Inc. 3 | * All rights reserved. 4 | * 5 | * This source code is licensed under the BSD-style license found in the 6 | * LICENSE file in the root directory of this source tree. An additional grant 7 | * of patent rights can be found in the PATENTS file in the same directory. 8 | */ 9 | 10 | #import "AppDelegate.h" 11 | 12 | #import "RCTBundleURLProvider.h" 13 | #import "RCTRootView.h" 14 | 15 | @implementation AppDelegate 16 | 17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 18 | { 19 | NSURL *jsCodeLocation; 20 | 21 | jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil]; 22 | 23 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 24 | moduleName:@"HelloWorldApp" 25 | initialProperties:nil 26 | launchOptions:launchOptions]; 27 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 28 | 29 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 30 | UIViewController *rootViewController = [UIViewController new]; 31 | rootViewController.view = rootView; 32 | self.window.rootViewController = rootViewController; 33 | [self.window makeKeyAndVisible]; 34 | return YES; 35 | } 36 | 37 | @end 38 | --------------------------------------------------------------------------------