├── .github
└── ISSUE_TEMPLATE.md
├── .gitignore
├── 1 - HOC (Deprecated)
├── README.md
├── config
│ ├── env.js
│ ├── jest
│ │ ├── CSSStub.js
│ │ └── FileStub.js
│ ├── paths.js
│ ├── polyfills.js
│ ├── webpack.config.dev.js
│ └── webpack.config.prod.js
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
├── scripts
│ ├── build.js
│ ├── start.js
│ └── test.js
└── src
│ ├── App.css
│ ├── App.js
│ ├── components
│ ├── ContactList.js
│ ├── ContactsApp.css
│ ├── ContactsApp.js
│ ├── HOC
│ │ ├── LoadingHOC.css
│ │ └── LoadingHOC.js
│ └── SearchBar.js
│ ├── index.css
│ └── index.js
├── 10 - Redux Thunk Tricks
├── README.md
├── package.json
├── public
│ ├── books
│ │ ├── gameofthrones.jpg
│ │ ├── harrypotter.jpg
│ │ ├── lotr.jpg
│ │ ├── murderorient.jpg
│ │ ├── neuromancer.jpg
│ │ ├── readyp1.jpg
│ │ └── sherlockholmes.jpg
│ ├── favicon.ico
│ └── index.html
└── src
│ ├── App.js
│ ├── actions
│ ├── book.js
│ ├── cart.js
│ └── user.js
│ ├── api
│ └── index.js
│ ├── components
│ ├── Auth.js
│ ├── BookDetails.css
│ └── BookDetails.js
│ ├── constants.js
│ ├── index.css
│ ├── index.js
│ ├── reducers
│ ├── books.js
│ ├── cart.js
│ ├── index.js
│ └── user.js
│ └── store.js
├── 11 - Recompose (Deprecated)
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── manifest.json
│ └── pictures
│ │ ├── classic.jpg
│ │ ├── fast.jpg
│ │ ├── intelligent.jpg
│ │ ├── thriller.jpg
│ │ ├── voodoo.jpg
│ │ └── walkers-biters.jpg
└── src
│ ├── App.js
│ ├── components
│ ├── Card.css
│ ├── Card.js
│ ├── Spinner.css
│ └── Spinner.js
│ ├── index.css
│ └── index.js
├── 12 - SSR pt1 (Deprecated)
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── bundle.js
│ ├── bundle.js.map
│ ├── css
│ │ ├── main.css
│ │ └── main.css.map
│ └── media
│ │ └── logo.svg
├── server.js
├── server.js.map
├── src
│ ├── browser
│ │ └── index.js
│ ├── server
│ │ └── index.js
│ └── shared
│ │ ├── App.css
│ │ ├── App.js
│ │ └── logo.svg
└── webpack.config.js
├── 13 - SSR pt2 (Deprecated)
├── README.md
├── episode-source-code(redux)
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ │ ├── bundle.js
│ │ ├── bundle.js.map
│ │ ├── css
│ │ │ ├── main.css
│ │ │ └── main.css.map
│ │ ├── favicon.ico
│ │ └── media
│ │ │ ├── logo.png
│ │ │ └── wizards.jpg
│ ├── server.js
│ ├── server.js.map
│ ├── src
│ │ ├── browser
│ │ │ └── index.js
│ │ ├── server
│ │ │ └── index.js
│ │ └── shared
│ │ │ ├── App.css
│ │ │ ├── App.js
│ │ │ ├── configureStore.js
│ │ │ ├── ducks.js
│ │ │ ├── home
│ │ │ ├── index.css
│ │ │ ├── index.js
│ │ │ ├── logo.png
│ │ │ └── wizards.jpg
│ │ │ ├── news
│ │ │ ├── NewsList.css
│ │ │ ├── NewsList.js
│ │ │ └── index.js
│ │ │ └── routes.js
│ └── webpack.config.js
└── episode-source-code
│ ├── home
│ ├── Home.css
│ ├── Home.js
│ ├── logo.png
│ └── wizards.jpg
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ ├── bundle.js
│ ├── bundle.js.map
│ ├── css
│ │ ├── main.css
│ │ └── main.css.map
│ ├── favicon.ico
│ └── media
│ │ ├── flags.png
│ │ ├── icons.svg
│ │ ├── logo.png
│ │ ├── w18.png
│ │ └── wizards.jpg
│ ├── server.js
│ ├── server.js.map
│ ├── src
│ ├── browser
│ │ └── index.js
│ ├── server
│ │ └── index.js
│ └── shared
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── news
│ │ ├── News.js
│ │ ├── NewsList.css
│ │ ├── NewsList.js
│ │ └── w18.png
│ │ └── routes.js
│ └── webpack.config.js
├── 14 - Big boring forms
├── .eslintcache
├── .gitignore
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
│ ├── App.css
│ ├── App.js
│ ├── ContactForm.css
│ ├── ContactForm.js
│ ├── index.css
│ └── index.js
├── 15 - React.memo
├── .eslintcache
├── .gitignore
├── README.md
├── knuth premature optimization.webp
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ ├── pictures
│ │ ├── classic.jpg
│ │ ├── fast.jpg
│ │ ├── intelligent.jpg
│ │ ├── thriller.jpg
│ │ ├── voodoo.jpg
│ │ └── walkers-biters.jpg
│ └── robots.txt
└── src
│ ├── App.css
│ ├── App.js
│ ├── Card.css
│ ├── Card.js
│ ├── index.css
│ └── index.js
├── 16 - Server components
├── .gitignore
├── .prettierignore
├── .prettierrc.js
├── README.md
├── credentials.json
├── package.json
├── public
│ ├── books
│ │ ├── gameofthrones.jpg
│ │ ├── harrypotter.jpg
│ │ ├── lotr.jpg
│ │ ├── murderorient.jpg
│ │ ├── neuromancer.jpg
│ │ ├── readyp1.jpg
│ │ └── sherlockholmes.jpg
│ ├── favicon.ico
│ └── index.html
├── scripts
│ ├── build.js
│ └── seed.js
├── server
│ ├── api.server.js
│ └── package.json
└── src
│ ├── App.server.js
│ ├── BookDetails.server.js
│ ├── BookList.client.js
│ ├── BookList.server.js
│ ├── BuyButton.client.js
│ ├── Cache.client.js
│ ├── Root.client.js
│ ├── SelectedBookContext.client.js
│ ├── SimilarBooks.server.js
│ ├── db.server.js
│ ├── index.client.css
│ └── index.client.js
├── 17 - An alternative to ejecting in CRA
└── README.md
├── 18 - Hook stale closures
├── .gitignore
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── App.css
│ ├── App.jsx
│ ├── index.css
│ └── main.jsx
└── vite.config.js
├── 19 - State machines
├── .gitignore
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── StopWatch.css
│ ├── StopWatch.jsx
│ ├── formatTime.js
│ ├── index.css
│ └── main.jsx
└── vite.config.js
├── 2 - Render Props
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
└── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── faac
│ └── ScrollPos.js
│ ├── index.css
│ └── index.js
├── 20 - Custom State machine Hook
├── .gitignore
├── README.md
├── index.html
├── package-lock.json
├── package.json
├── src
│ ├── StopWatch.css
│ ├── StopWatch.tsx
│ ├── formatTime.js
│ ├── index.css
│ └── main.jsx
├── tsconfig.json
└── vite.config.js
├── 3 - Children API
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
└── src
│ ├── App.css
│ ├── App.js
│ ├── Parent.js
│ ├── SlideShow.css
│ ├── SlideShow.js
│ ├── index.css
│ └── index.js
├── 4 - Context pt1 (Deprecated)
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
└── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── components
│ ├── ContentPanel.js
│ ├── InternalPanel.js
│ └── Panel.js
│ ├── index.css
│ ├── index.js
│ └── locales
│ ├── en.json
│ └── pt.json
├── 5 - Context pt2 (Deprecated)
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ └── index.html
└── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── components
│ ├── ContentPanel.js
│ ├── InternalPanel.js
│ ├── Panel.js
│ └── WithLocaleHOC.js
│ ├── index.css
│ ├── index.js
│ └── locales
│ ├── Locale.js
│ ├── en.json
│ └── pt.json
├── 6 - Redux Middleware
├── README.md
├── package.json
├── public
│ └── index.html
└── src
│ ├── actions
│ └── index.js
│ ├── components
│ ├── Footer.js
│ ├── Link.js
│ ├── Todo.css
│ ├── Todo.js
│ └── TodoList.js
│ ├── constants.js
│ ├── containers
│ ├── AddTodo.js
│ ├── App.js
│ ├── FilterLink.js
│ └── VisibleTodoList.js
│ ├── index.css
│ ├── index.js
│ └── reducers
│ ├── index.js
│ ├── todos.js
│ └── visibilityFilter.js
├── 7 - HMR (Deprecated)
├── README.md
├── hmr-quick
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ └── index.html
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── index.css
│ │ ├── index.js
│ │ └── logo.svg
└── hrm-with-react-hot-loader
│ ├── .gitignore
│ ├── README.md
│ ├── config
│ ├── env.js
│ ├── jest
│ │ ├── CSSStub.js
│ │ └── FileStub.js
│ ├── paths.js
│ ├── polyfills.js
│ ├── webpack.config.dev.js
│ └── webpack.config.prod.js
│ ├── package.json
│ ├── public
│ ├── favicon.ico
│ └── index.html
│ ├── scripts
│ ├── build.js
│ ├── start.js
│ └── test.js
│ └── src
│ ├── App.css
│ ├── App.js
│ ├── App.test.js
│ ├── index.css
│ ├── index.js
│ └── logo.svg
├── 8 - Selectors in Redux
├── README.md
├── package.json
├── public
│ ├── fakeserver_images
│ │ ├── deluxe-city.jpg
│ │ ├── deluxe-ocean.jpg
│ │ ├── grandlux.jpg
│ │ ├── royal.jpg
│ │ ├── standard-city.jpg
│ │ └── standard-ocean.jpg
│ ├── favicon.ico
│ └── index.html
├── src
│ ├── App.css
│ ├── App.js
│ ├── actions
│ │ ├── auth.js
│ │ └── rooms.js
│ ├── api
│ │ └── fakeApi.js
│ ├── components
│ │ ├── SlideShow.css
│ │ ├── SlideShow.js
│ │ └── background.jpg
│ ├── constants.js
│ ├── index.css
│ ├── index.js
│ ├── logo.png
│ └── reducers
│ │ ├── auth.js
│ │ ├── index.js
│ │ └── rooms.js
└── yarn.lock
├── 9 - Immutability in JS
├── README.md
├── index.js
├── package-lock.json
└── package.json
├── LICENSE
└── README.md
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # dependencies
2 | node_modules
3 |
4 | # misc
5 | .DS_Store
6 | .env
7 | npm-debug.log
8 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/README.md:
--------------------------------------------------------------------------------
1 | # Higher Order Components
2 |
3 | ReactCasts, episode 1.
4 |
5 | In simple terms, we could say that a Higher Order Component is a function that accepts a component as parameter and returns another component that wraps it.
6 |
7 | This screencast shows how to create Higher Order Components and give examples of how it can be useful.
8 |
9 | Screencast video:
10 | https://www.youtube.com/watch?v=LTunyI2Oyzw
11 |
12 | # Outline
13 |
14 | - What is a Higher Order Component
15 | - Render highjacking
16 | - Usage as a decorator
17 | - Using Curried functions for configuration
18 | - Manipulating Props
19 |
20 | # Build & Run Instructions
21 |
22 |
23 | 1. To build and run the code in this directory, ensure you have [npm](https://www.npmjs.com) installed
24 |
25 | 2. Install
26 | ```
27 | npm install
28 | ```
29 |
30 | 3. Start the application
31 | ```
32 | npm start
33 | ```
34 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/config/env.js:
--------------------------------------------------------------------------------
1 | // Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
2 | // injected into the application via DefinePlugin in Webpack configuration.
3 |
4 | var REACT_APP = /^REACT_APP_/i;
5 |
6 | function getClientEnvironment(publicUrl) {
7 | return Object
8 | .keys(process.env)
9 | .filter(key => REACT_APP.test(key))
10 | .reduce((env, key) => {
11 | env['process.env.' + key] = JSON.stringify(process.env[key]);
12 | return env;
13 | }, {
14 | // Useful for determining whether we’re running in production mode.
15 | // Most importantly, it switches React into the correct mode.
16 | 'process.env.NODE_ENV': JSON.stringify(
17 | process.env.NODE_ENV || 'development'
18 | ),
19 | // Useful for resolving the correct path to static assets in `public`.
20 | // For example,
.
21 | // This should only be used as an escape hatch. Normally you would put
22 | // images into the `src` and `import` them in code to get their paths.
23 | 'process.env.PUBLIC_URL': JSON.stringify(publicUrl)
24 | });
25 | }
26 |
27 | module.exports = getClientEnvironment;
28 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/config/jest/CSSStub.js:
--------------------------------------------------------------------------------
1 | module.exports = {};
2 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/config/jest/FileStub.js:
--------------------------------------------------------------------------------
1 | module.exports = "test-file-stub";
2 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/config/paths.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 | var fs = require('fs');
3 |
4 | // Make sure any symlinks in the project folder are resolved:
5 | // https://github.com/facebookincubator/create-react-app/issues/637
6 | var appDirectory = fs.realpathSync(process.cwd());
7 | function resolveApp(relativePath) {
8 | return path.resolve(appDirectory, relativePath);
9 | }
10 |
11 | // We support resolving modules according to `NODE_PATH`.
12 | // This lets you use absolute paths in imports inside large monorepos:
13 | // https://github.com/facebookincubator/create-react-app/issues/253.
14 |
15 | // It works similar to `NODE_PATH` in Node itself:
16 | // https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
17 |
18 | // We will export `nodePaths` as an array of absolute paths.
19 | // It will then be used by Webpack configs.
20 | // Jest doesn’t need this because it already handles `NODE_PATH` out of the box.
21 |
22 | var nodePaths = (process.env.NODE_PATH || '')
23 | .split(process.platform === 'win32' ? ';' : ':')
24 | .filter(Boolean)
25 | .map(resolveApp);
26 |
27 | // config after eject: we're in ./config/
28 | module.exports = {
29 | appBuild: resolveApp('build'),
30 | appPublic: resolveApp('public'),
31 | appHtml: resolveApp('public/index.html'),
32 | appIndexJs: resolveApp('src/index.js'),
33 | appPackageJson: resolveApp('package.json'),
34 | appSrc: resolveApp('src'),
35 | testsSetup: resolveApp('src/setupTests.js'),
36 | appNodeModules: resolveApp('node_modules'),
37 | ownNodeModules: resolveApp('node_modules'),
38 | nodePaths: nodePaths
39 | };
40 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/config/polyfills.js:
--------------------------------------------------------------------------------
1 | if (typeof Promise === 'undefined') {
2 | // Rejection tracking prevents a common issue where React gets into an
3 | // inconsistent state due to an error, but it gets swallowed by a Promise,
4 | // and the user has no idea what causes React's erratic future behavior.
5 | require('promise/lib/rejection-tracking').enable();
6 | window.Promise = require('promise/lib/es6-extensions.js');
7 | }
8 |
9 | // fetch() polyfill for making API calls.
10 | require('whatwg-fetch');
11 |
12 | // Object.assign() is commonly used with React.
13 | // It will use the native implementation if it's present and isn't buggy.
14 | Object.assign = require('object-assign');
15 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/1 - HOC (Deprecated)/public/favicon.ico
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 | React App
17 |
18 |
19 |
20 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/scripts/test.js:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'test';
2 | process.env.PUBLIC_URL = '';
3 |
4 | // Load environment variables from .env file. Surpress warnings using silent
5 | // if this file is missing. dotenv will never modify any environment variables
6 | // that have already been set.
7 | // https://github.com/motdotla/dotenv
8 | require('dotenv').config({silent: true});
9 |
10 | const jest = require('jest');
11 | const argv = process.argv.slice(2);
12 |
13 | // Watch unless on CI
14 | if (!process.env.CI) {
15 | argv.push('--watch');
16 | }
17 |
18 |
19 | jest.run(argv);
20 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | width: 300px;
3 | margin: auto;
4 | }
5 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import ContactsApp from './components/ContactsApp';
3 | import './App.css';
4 |
5 | class App extends Component {
6 | state = { contacts: [] }
7 |
8 | componentDidMount() {
9 | fetch('https://api.randomuser.me/?nat=us,gb&results=50')
10 | .then(response => response.json())
11 | .then(parsedResponse => parsedResponse.results.map(user => (
12 | {
13 | name: `${user.name.first} ${user.name.last}`,
14 | email: user.email,
15 | thumbnail: user.picture.thumbnail
16 | }
17 | )))
18 | .then(contacts => this.setState({contacts}));
19 | }
20 |
21 | render() {
22 | return (
23 |
24 |
25 |
26 | );
27 | }
28 | }
29 |
30 | export default App;
31 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/src/components/ContactList.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 |
3 | const ContactList = ({ contacts, filterText }) => {
4 | const filteredContacts = contacts.filter(contact => contact.name.indexOf(filterText) !== -1);
5 |
6 | return(
7 |
17 | )
18 | }
19 |
20 | ContactList.propTypes = {
21 | contacts: PropTypes.arrayOf(PropTypes.object),
22 | filterText: PropTypes.string.isRequired
23 | }
24 |
25 | export default ContactList;
26 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/src/components/ContactsApp.css:
--------------------------------------------------------------------------------
1 | .contactApp {
2 | width: 300px;
3 | }
4 |
5 | .contactApp > *{
6 | width: 100%;
7 | }
8 |
9 | ul {
10 | padding: 0;
11 | }
12 |
13 | li {
14 | list-style: none;
15 | margin: 5px;
16 | }
17 |
18 | .contactData {
19 | padding-top: 5px;
20 | height: 40px;
21 | }
22 |
23 | li img{
24 | border-radius: 50%;
25 | margin-right: 10px;
26 | float: left;
27 | }
28 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/src/components/ContactsApp.js:
--------------------------------------------------------------------------------
1 | import React, { Component, PropTypes } from 'react';
2 | import SearchBar from './SearchBar';
3 | import ContactList from './ContactList';
4 | import LoadingHOC from './HOC/LoadingHOC'
5 | import './ContactsApp.css';
6 |
7 | @LoadingHOC('contacts')
8 | class ContactsApp extends Component {
9 | state = {
10 | filterText: ''
11 | };
12 |
13 | static propTypes = {
14 | contacts: PropTypes.arrayOf(
15 | PropTypes.shape({
16 | thumbnail: PropTypes.string.isRequired,
17 | name: PropTypes.string.isRequired,
18 | email: PropTypes.string
19 | })
20 | ).isRequired,
21 | loadingTime: PropTypes.string
22 | }
23 |
24 | handleUserInput = (searchTerm) => {
25 | this.setState({filterText: searchTerm})
26 | }
27 |
28 | render() {
29 | const { loadingTime } = this.props;
30 | return(
31 |
32 |
34 |
36 | Loading time {loadingTime} seconds
37 |
38 | )
39 | }
40 | }
41 |
42 |
43 | export default ContactsApp;
44 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/src/components/HOC/LoadingHOC.css:
--------------------------------------------------------------------------------
1 | .loader {
2 | position: absolute;
3 | top: 50%;
4 | left: 50%;
5 | -webkit-transform: translateX(-50%) translateY(-50%);
6 | -ms-transform: translateX(-50%) translateY(-50%);
7 | transform: translateX(-50%) translateY(-50%);
8 | }
9 |
10 | /* Static Shape */
11 |
12 | .loader:before {
13 | position: absolute;
14 | content: '';
15 | top: 0%;
16 | left: 50%;
17 | width: 100%;
18 | height: 100%;
19 | border-radius: 500rem;
20 | border: 0.2em solid rgba(0, 0, 0, 0.1);
21 | }
22 |
23 | /* Active Shape */
24 |
25 | .loader:after {
26 | position: absolute;
27 | content: '';
28 | top: 0%;
29 | left: 50%;
30 | width: 100%;
31 | height: 100%;
32 | animation: loader 0.6s linear;
33 | animation-iteration-count: infinite;
34 | border-radius: 500rem;
35 | border-color: #767676 transparent transparent;
36 | border-style: solid;
37 | border-width: 0.2em;
38 | box-shadow: 0px 0px 0px 1px transparent;
39 | }
40 |
41 | /* Active Animation */
42 |
43 | @-webkit-keyframes loader {
44 | from {
45 | -webkit-transform: rotate(0deg);
46 | transform: rotate(0deg);
47 | }
48 |
49 | to {
50 | -webkit-transform: rotate(360deg);
51 | transform: rotate(360deg);
52 | }
53 | }
54 |
55 | @keyframes loader {
56 | from {
57 | -webkit-transform: rotate(0deg);
58 | transform: rotate(0deg);
59 | }
60 |
61 | to {
62 | -webkit-transform: rotate(360deg);
63 | transform: rotate(360deg);
64 | }
65 | }
66 |
67 | .loader:before,
68 | .loader:after {
69 | width: 2.28571429rem;
70 | height: 2.28571429rem;
71 | margin: 0em;
72 | }
73 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/src/components/HOC/LoadingHOC.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import './LoadingHOC.css';
3 |
4 | const isEmpty = (prop) => (
5 | prop === null ||
6 | prop === undefined ||
7 | (prop.hasOwnProperty('length') && prop.length === 0) ||
8 | (prop.constructor === Object && Object.keys(prop).length === 0)
9 | );
10 |
11 | const LoadingHOC = (loadingProp) => (WrappedComponent) => {
12 | return class LoadingHOC extends Component {
13 | componentDidMount(){
14 | this.startTimer = Date.now();
15 | }
16 |
17 | componentWillUpdate(nextProps){
18 | if(!isEmpty(nextProps[loadingProp])) {
19 | this.endTimer = Date.now();
20 | }
21 | }
22 |
23 | render() {
24 | const myProps = {
25 | loadingTime: ((this.endTimer - this.startTimer)/1000).toFixed(2),
26 | };
27 |
28 | return isEmpty(this.props[loadingProp]) ? : ;
29 | }
30 | }
31 | }
32 |
33 |
34 | export default LoadingHOC;
35 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/src/components/SearchBar.js:
--------------------------------------------------------------------------------
1 | import React, { PropTypes } from 'react';
2 |
3 | const getInput = (event) => event.target.value;
4 |
5 | const SearchBar = ({ filterText, onUserInput }) => (
6 | onUserInput(getInput(event)) }
11 | />
12 | );
13 |
14 | SearchBar.propTypes = {
15 | onUserInput: PropTypes.func.isRequired,
16 | filterText: PropTypes.string.isRequired
17 | };
18 |
19 | export default SearchBar;
20 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
--------------------------------------------------------------------------------
/1 - HOC (Deprecated)/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 | import './index.css';
5 |
6 | ReactDOM.render(
7 | ,
8 | document.getElementById('root')
9 | );
10 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/README.md:
--------------------------------------------------------------------------------
1 | # Redux Thunk Tricks
2 |
3 | ReactCasts, episode 10.
4 |
5 | Redux Thunk is the most used library for side effects and asyncronous calls in Redux - and that's for a reason. But despite being so used, there are a few useful thunk tricks that aren't yet commonplace, so in this episode I'll share some pieces of thunk knowledge that might help you build better applications.
6 |
7 | Screencast video:
8 | https://youtu.be/xihoZZU0gao
9 |
10 | # Outline
11 |
12 | - The first tip is very simple: You can return values from thunks, and this can be useful, for example, for asynchronous orchestration.
13 |
14 | - The second tip is about thunk's getState, and how it can be a bad idea to rely on this mechanism for accessing data.
15 |
16 | - The third tip is about using thunk withExtraArguments to make your thunks easy to test and run on multiple environments.
17 |
18 |
19 | # Build & Run Instructions
20 |
21 | 1. To build and run the code in this directory, ensure you have [npm](https://www.npmjs.com) installed
22 |
23 | 2. Install
24 | ```
25 | npm install
26 | ```
27 |
28 | 3. Start the application
29 | ```
30 | npm start
31 | ```
32 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bookstore",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "lodash.intersection": "^4.4.0",
7 | "react": "^15.5.4",
8 | "react-dom": "^15.5.4",
9 | "react-redux": "^5.0.4",
10 | "redux": "^3.6.0",
11 | "semantic-ui-react": "^0.68.2"
12 | },
13 | "devDependencies": {
14 | "react-scripts": "0.9.5"
15 | },
16 | "scripts": {
17 | "start": "react-scripts start",
18 | "build": "react-scripts build",
19 | "test": "react-scripts test --env=jsdom",
20 | "eject": "react-scripts eject"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/public/books/gameofthrones.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/10 - Redux Thunk Tricks/public/books/gameofthrones.jpg
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/public/books/harrypotter.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/10 - Redux Thunk Tricks/public/books/harrypotter.jpg
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/public/books/lotr.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/10 - Redux Thunk Tricks/public/books/lotr.jpg
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/public/books/murderorient.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/10 - Redux Thunk Tricks/public/books/murderorient.jpg
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/public/books/neuromancer.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/10 - Redux Thunk Tricks/public/books/neuromancer.jpg
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/public/books/readyp1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/10 - Redux Thunk Tricks/public/books/readyp1.jpg
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/public/books/sherlockholmes.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/10 - Redux Thunk Tricks/public/books/sherlockholmes.jpg
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/10 - Redux Thunk Tricks/public/favicon.ico
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
17 | React App
18 |
19 |
20 |
21 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Dropdown, Segment } from 'semantic-ui-react'
3 | import Auth from './components/Auth';
4 | import BookDetails from './components/BookDetails';
5 |
6 | class App extends Component {
7 | state = {
8 | selectedId: null
9 | }
10 | render() {
11 | return (
12 |
13 |
14 | { this.state.selectedId ?
15 |
16 | :
17 |
18 | this.setState({selectedId: selected.value})}
30 | fluid
31 | search
32 | selection
33 | />
34 |
35 | }
36 |
37 | );
38 | }
39 | }
40 |
41 | export default App;
42 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/actions/book.js:
--------------------------------------------------------------------------------
1 | import {
2 | BOOK_REQUESTING, BOOK_SUCCESS, BOOK_FAILURE, SIMILAR_REQUESTING, SIMILAR_SUCCESS, SIMILAR_FAILURE
3 | } from '../constants';
4 |
5 | const entryLoading = id => ({ type: BOOK_REQUESTING, payload: id });
6 | const entryLoaded = book => ({ type: BOOK_SUCCESS, payload: book });
7 | const entryLoadError = () => ({ type: BOOK_FAILURE });
8 |
9 | export const requestBook = id => (
10 | (dispatch, getState, api) => {
11 | dispatch(entryLoading(id));
12 | return api.fetchBook(id)
13 | .then(book => {
14 | dispatch( entryLoaded(book) );
15 | return book;
16 | })
17 | .catch(err => {
18 | dispatch( entryLoadError() );
19 | });
20 | }
21 | );
22 |
23 | const similarEntriesLoading = tags => ({ type: SIMILAR_REQUESTING, payload: tags });
24 | const similarEntriesLoaded = books => ({ type: SIMILAR_SUCCESS, payload: books });
25 | const similarEntriesLoadError = () => ({ type: SIMILAR_FAILURE });
26 |
27 | export const requestBooksByTags = (id, tags) => (
28 | (dispatch, getState, api) => {
29 | dispatch(similarEntriesLoading(tags));
30 | api.fetchBooksByTags(tags)
31 | .then(books => {
32 | dispatch( similarEntriesLoaded(books.filter(p => p.id !== id)) );
33 | })
34 | .catch(err => {
35 | dispatch( similarEntriesLoadError() );
36 | });
37 | }
38 | );
39 |
40 |
41 | export const requestBookAndSimilars = (id) => (
42 | dispatch => {
43 | dispatch(requestBook(id)).then(book => dispatch(requestBooksByTags(id, book.tags)));
44 | }
45 | )
46 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/actions/cart.js:
--------------------------------------------------------------------------------
1 | import { ADDED_TO_CART } from '../constants';
2 |
3 | const added = id => ({ type: ADDED_TO_CART, payload: id });
4 |
5 | export const addToCart = (bookId) => (
6 | (dispatch, getState, api) => {
7 | const user = getState().user;
8 | if(user){
9 | api.addToCart(bookId)
10 | .then(dispatch(added(bookId)));
11 | }
12 | }
13 | );
14 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/actions/user.js:
--------------------------------------------------------------------------------
1 | import {
2 | LOG_USER, LOGGED_USER, USER_FAILURE
3 | } from '../constants';
4 |
5 | const userLoading = id => ({ type: LOG_USER, payload: id });
6 | const userLoaded = user => ({ type: LOGGED_USER, payload: user });
7 | const userLoadError = () => ({ type: USER_FAILURE });
8 |
9 | export const getUser = () => (
10 | (dispatch, getState, api) => {
11 | dispatch(userLoading);
12 | return api.getUser()
13 | .then(user => {
14 | dispatch( userLoaded(user) );
15 | return user;
16 | })
17 | .catch(err => {
18 | dispatch( userLoadError() );
19 | });
20 | }
21 | );
22 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/components/Auth.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { connect } from 'react-redux';
3 | import { getUser } from '../actions/user';
4 | import { Button } from 'semantic-ui-react'
5 |
6 | class Auth extends Component {
7 | render() {
8 | const { user, getUser } = this.props
9 | return (
10 |
13 | )
14 | }
15 | }
16 |
17 | const mapStateToProps = (state) => {
18 | return { user: state.user };
19 | }
20 |
21 | const mapDispatchToProps = {
22 | getUser
23 | }
24 |
25 | export default connect(mapStateToProps, mapDispatchToProps)(Auth);
26 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/components/BookDetails.css:
--------------------------------------------------------------------------------
1 | .cover {
2 | display: block;
3 | height: 305px;
4 | float: left;
5 | margin-right: 15px;
6 | }
7 |
8 | .segment::after {
9 | content: '';
10 | display: block;
11 | clear: both;
12 | }
13 |
14 | .similar {
15 | margin-top: 29px;
16 | }
17 |
18 | .similar_cover {
19 | display: block;
20 | height: 125px;
21 | float: left;
22 | margin-right: 15px;
23 | }
24 |
25 | .segment .ui.button {
26 | display: block;
27 | margin: 15px 0;
28 | }
29 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/components/BookDetails.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Segment, Label, Button } from 'semantic-ui-react'
3 | import { connect } from 'react-redux';
4 | import { requestBookAndSimilars } from '../actions/book';
5 | import { addToCart } from '../actions/cart';
6 |
7 | import './BookDetails.css';
8 |
9 | class BookDetails extends Component {
10 | componentDidMount() {
11 | this.props.requestBookAndSimilars(this.props.id);
12 | }
13 |
14 | handleAddToCart = () => {
15 | this.props.addToCart(this.props.id);
16 | }
17 |
18 | render() {
19 | const { id, series, title, author, image, tags, similarBooks } = this.props;
20 | return (
21 |
22 | {series}
23 |
24 |
25 | ID: {id} - {title}
26 | By {author}
27 | { tags && tags.map(tag => ) }
28 |
29 |
30 |
You might also like:
31 | { similarBooks && similarBooks.map(similar => (
32 |

33 | )) }
34 |
35 |
36 |
37 |
38 | )
39 | }
40 | }
41 |
42 | const mapStateToProps = (state) => {
43 | const { selectedBook, similar } = state.books;
44 | return {
45 | ...selectedBook,
46 | series: selectedBook.series || selectedBook.title,
47 | similarBooks: similar
48 | }
49 | }
50 |
51 | const mapDispatchToProps = {
52 | requestBookAndSimilars,
53 | addToCart
54 | }
55 |
56 | export default connect(mapStateToProps, mapDispatchToProps)(BookDetails);
57 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/constants.js:
--------------------------------------------------------------------------------
1 | export const LOG_USER = 'LOG_USER';
2 | export const LOGGED_USER = 'LOGGED_USER';
3 | export const USER_FAILURE = 'USER_FAILURE';
4 |
5 | export const BOOK_REQUESTING = 'BOOK_REQUESTING';
6 | export const BOOK_SUCCESS = 'BOOK_SUCCESS';
7 | export const BOOK_FAILURE = 'BOOK_FAILURE';
8 |
9 | export const SIMILAR_REQUESTING = 'SIMILAR_REQUESTING';
10 | export const SIMILAR_SUCCESS = 'SIMILAR_SUCCESS';
11 | export const SIMILAR_FAILURE = 'SIMILAR_FAILURE';
12 |
13 | export const ADDED_TO_CART = 'ADDED_TO_CART';
14 |
15 | export const TOGGLE_SIDEBAR = 'TOGGLE_SIDEBAR';
16 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 10px;
3 | font-family: sans-serif;
4 | }
5 |
6 | h1 {
7 | margin: 0 0 5px 0;
8 | font-size: 18px;
9 | color: #333;
10 | }
11 |
12 |
13 | h2 {
14 | margin: 0 0 5px 0;
15 | font-size: 15px;
16 | color: #333;
17 | }
18 |
19 | h3 {
20 | margin: 0 0 5px 0;
21 | font-size: 14px;
22 | color: #773;
23 | }
24 |
25 | .clear::after {
26 | content: '';
27 | display: block;
28 | clear: both;
29 | }
30 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { Provider } from 'react-redux';
4 | import App from './App';
5 | import store from './store';
6 | import './index.css';
7 |
8 | ReactDOM.render(
9 |
10 |
11 | ,
12 | document.getElementById('root')
13 | );
14 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/reducers/books.js:
--------------------------------------------------------------------------------
1 | import { BOOK_SUCCESS, SIMILAR_SUCCESS } from '../constants';
2 |
3 | export default (state = { selectedBook: {}, similar: [] }, action) => {
4 | switch (action.type) {
5 | case BOOK_SUCCESS:
6 | return { selectedBook: action.payload, similar: [] };
7 |
8 | case SIMILAR_SUCCESS:
9 | return {...state, similar: action.payload };
10 |
11 | default:
12 | return state;
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/reducers/cart.js:
--------------------------------------------------------------------------------
1 | import { ADDED_TO_CART } from '../constants';
2 |
3 | export default (state = [], action) => {
4 | switch (action.type) {
5 | case ADDED_TO_CART:
6 | return [...state, action.payload];
7 |
8 | default:
9 | return state;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/reducers/index.js:
--------------------------------------------------------------------------------
1 | import { combineReducers } from 'redux';
2 | import books from './books';
3 | import user from './user';
4 | import cart from './cart';
5 |
6 | export default combineReducers({ books, user, cart })
7 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/reducers/user.js:
--------------------------------------------------------------------------------
1 | import { LOGGED_USER } from '../constants';
2 |
3 | export default (state = null, action) => {
4 | switch (action.type) {
5 | case LOGGED_USER:
6 | return action.payload;
7 |
8 | default:
9 | return state;
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/10 - Redux Thunk Tricks/src/store.js:
--------------------------------------------------------------------------------
1 | import api from './api';
2 | import { createStore, applyMiddleware } from 'redux';
3 | import thunk from 'redux-thunk';
4 | import reducer from './reducers';
5 |
6 |
7 | export default createStore(
8 | reducer,
9 | applyMiddleware(thunk.withExtraArgument(api))
10 | );
11 |
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/README.md:
--------------------------------------------------------------------------------
1 | # Recompose
2 |
3 | ReactCasts, episode 11.
4 |
5 | Recompose is a library that provides an assortment of higher order components that let's you "enhance" React functional components, so to speak, and do things all sort of things - including but not limited to local state and lifecycle hooks.
6 |
7 | Screencast video:
8 | https://youtu.be/SQtrgiLy3Fo
9 |
10 | # Outline
11 |
12 | - Understanding Recompose
13 |
14 | - withStata for local component State
15 |
16 | - branch and renderComponent
17 |
18 | - composing HOCs
19 |
20 |
21 | # Build & Run Instructions
22 |
23 | 1. To build and run the code in this directory, ensure you have [npm](https://www.npmjs.com) installed
24 |
25 | 2. Install
26 | ```
27 | npm install
28 | ```
29 |
30 | 3. Start the application
31 | ```
32 | npm start
33 | ```
34 |
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "zombies",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^15.5.4",
7 | "react-dom": "^15.5.4",
8 | "recompose": "^0.23.4"
9 | },
10 | "devDependencies": {
11 | "react-scripts": "1.0.7"
12 | },
13 | "scripts": {
14 | "start": "react-scripts start",
15 | "build": "react-scripts build",
16 | "test": "react-scripts test --env=jsdom",
17 | "eject": "react-scripts eject"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/11 - Recompose (Deprecated)/public/favicon.ico
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | React App
23 |
24 |
25 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "192x192",
8 | "type": "image/png"
9 | }
10 | ],
11 | "start_url": "./index.html",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/public/pictures/classic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/11 - Recompose (Deprecated)/public/pictures/classic.jpg
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/public/pictures/fast.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/11 - Recompose (Deprecated)/public/pictures/fast.jpg
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/public/pictures/intelligent.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/11 - Recompose (Deprecated)/public/pictures/intelligent.jpg
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/public/pictures/thriller.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/11 - Recompose (Deprecated)/public/pictures/thriller.jpg
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/public/pictures/voodoo.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/11 - Recompose (Deprecated)/public/pictures/voodoo.jpg
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/public/pictures/walkers-biters.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cassiozen/ReactCasts/947567bfa8af59d9f82fe4b2c03a6fb4d998d74b/11 - Recompose (Deprecated)/public/pictures/walkers-biters.jpg
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import Card from './components/Card';
3 |
4 | import Spinner from './components/Spinner';
5 | import { branch, renderComponent, lifecycle, compose } from 'recompose';
6 |
7 | const App = ({zombies}) => {
8 | return (
9 |
10 | {
11 | zombies.map(zombie => (
12 |
18 | ))
19 | }
20 |
21 | );
22 | }
23 |
24 |
25 | const enhance = compose(
26 | lifecycle({
27 | componentDidMount() {
28 | this.props.checkAuth()
29 | }
30 | }),
31 |
32 | branch(
33 | (props) => props.zombies.length === 0,
34 | renderComponent(Spinner)
35 | )
36 | );
37 |
38 | export default enhance(App);
39 |
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/src/components/Card.css:
--------------------------------------------------------------------------------
1 | .card {
2 | float: left;
3 | width: 360px;
4 | margin: 10px;
5 | padding: 16px 24px;
6 | background-color: #fff;
7 | border-radius: 4px;
8 | box-shadow: 0 2px 8px 0 #d9d9d9;
9 | }
10 |
11 | .card.open .header::before {
12 | content: "▼ "
13 | }
14 |
15 | .card.closed .header::before {
16 | content: "► "
17 | }
18 |
19 |
20 |
21 | .header {
22 | font-weight: bold;
23 | cursor: pointer;
24 | }
25 |
26 |
27 | .card.closed .body {
28 | display: none;
29 | }
30 |
31 |
32 | .body > img {
33 | margin: 16px -24px 16px;
34 | width: calc(100% + 16px + 16px + 16px);
35 | }
36 |
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/src/components/Card.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { withState, withHandlers, compose } from 'recompose';
3 | import './Card.css';
4 |
5 |
6 | const Card = ({opened, handleClick, title, picture, description}) => {
7 | return (
8 |
9 |
{title}
10 |
11 |

12 |
{description}
13 |
14 |
15 | );
16 | }
17 |
18 | const enhance = compose(
19 | withState('opened', 'setOpened', true),
20 | withHandlers({
21 | handleClick: props => event => {
22 | props.setOpened(!props.opened)
23 | },
24 | })
25 | )
26 |
27 |
28 |
29 | export default enhance(Card);
30 |
31 |
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/src/components/Spinner.css:
--------------------------------------------------------------------------------
1 | .spinner,
2 | .spinner:after {
3 | border-radius: 50%;
4 | width: 10em;
5 | height: 10em;
6 | }
7 | .spinner {
8 | margin: 60px auto;
9 | font-size: 10px;
10 | position: relative;
11 | text-indent: -9999em;
12 | border-top: 1.1em solid rgba(0, 0, 0, 0.2);
13 | border-right: 1.1em solid rgba(0, 0, 0, 0.2);
14 | border-bottom: 1.1em solid rgba(0, 0, 0, 0.2);
15 | border-left: 1.1em solid #000000;
16 | transform: translateZ(0);
17 | animation: spin 1.1s infinite linear;
18 | }
19 |
20 | @keyframes spin {
21 | 0% {
22 | transform: rotate(0deg);
23 | }
24 | 100% {
25 | transform: rotate(360deg);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/src/components/Spinner.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import './Spinner.css';
3 |
4 |
5 | const Spinner = () => {
6 | return Loading...
;
7 | }
8 |
9 |
10 | export default Spinner;
11 |
12 |
--------------------------------------------------------------------------------
/11 - Recompose (Deprecated)/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
7 | h1 {
8 | font-size: 30px;
9 | }
10 |
--------------------------------------------------------------------------------
/12 - SSR pt1 (Deprecated)/README.md:
--------------------------------------------------------------------------------
1 | # Server Side Rendering
2 |
3 | ReactCasts, episode 12.
4 |
5 | Server Side rendering means rendering your React components on the Server, and sending HTML pages pre-populated - This can lead to a better user experience and Search Engine discoverability.
6 |
7 | On the browser, when the javascript runs, react will realise that the component is already there and take over for front-end interactivity, skipping the initial render.
8 |
9 |
10 | Screencast video:
11 | https://youtu.be/tsEHfL-Ul1Y
12 |
13 | # Outline
14 |
15 | - Server side rendering benefits
16 |
17 | - Build Systems
18 |
19 | - Code organization (browser, server & shared)
20 |
21 | - Webpack configuration
22 |
23 | - browser-specific code
24 |
25 | - Server code (including express)
26 |
27 |
28 | # Build & Run Instructions
29 |
30 | 1. To build and run the code in this directory, ensure you have [npm](https://www.npmjs.com) installed
31 |
32 | 2. Install
33 | ```
34 | npm install
35 | ```
36 |
37 | 3. Start the application
38 | ```
39 | npm run start-dev
40 | ```
41 |
--------------------------------------------------------------------------------
/12 - SSR pt1 (Deprecated)/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-ssr",
3 | "version": "0.1.0",
4 | "description": "",
5 | "main": "server.js",
6 | "scripts": {
7 | "start-dev": "cross-env NODE_ENV=development webpack -w & cross-env NODE_ENV=development node server.js",
8 | "test": "echo \"Error: no test specified\" && exit 1"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "express": "^4.15.3",
15 | "react": "^15.6.1",
16 | "react-dom": "^15.6.1"
17 | },
18 | "devDependencies": {
19 | "autoprefixer": "^7.1.2",
20 | "babel-core": "^6.25.0",
21 | "babel-loader": "^7.1.1",
22 | "babel-preset-react-app": "^3.0.1",
23 | "cross-env": "^5.1.3",
24 | "css-loader": "^0.28.4",
25 | "extract-text-webpack-plugin": "^2.1.2",
26 | "file-loader": "^0.11.2",
27 | "postcss-loader": "^2.0.6",
28 | "webpack": "^3.1.0"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/12 - SSR pt1 (Deprecated)/public/css/main.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: sans-serif;
5 | }
6 |
7 | .App {
8 | text-align: center;
9 | }
10 |
11 | .App-logo {
12 | -webkit-animation: App-logo-spin infinite 20s linear;
13 | animation: App-logo-spin infinite 20s linear;
14 | height: 80px;
15 | }
16 |
17 | .App-header {
18 | background-color: #222;
19 | height: 150px;
20 | padding: 20px;
21 | color: white;
22 | }
23 |
24 | .App-intro {
25 | font-size: large;
26 | }
27 |
28 | @-webkit-keyframes App-logo-spin {
29 | from {
30 | -webkit-transform: rotate(0deg);
31 | transform: rotate(0deg);
32 | }
33 | to {
34 | -webkit-transform: rotate(360deg);
35 | transform: rotate(360deg);
36 | }
37 | }
38 |
39 | @keyframes App-logo-spin {
40 | from {
41 | -webkit-transform: rotate(0deg);
42 | transform: rotate(0deg);
43 | }
44 | to {
45 | -webkit-transform: rotate(360deg);
46 | transform: rotate(360deg);
47 | }
48 | }
49 |
50 | /*# sourceMappingURL=main.css.map*/
--------------------------------------------------------------------------------
/12 - SSR pt1 (Deprecated)/public/css/main.css.map:
--------------------------------------------------------------------------------
1 | {"version":3,"file":"public/css/main.css","sources":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","sourceRoot":""}
--------------------------------------------------------------------------------
/12 - SSR pt1 (Deprecated)/src/browser/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { render } from "react-dom";
3 | import App from "../shared/App";
4 |
5 | render(, document.getElementById("root"));
6 |
--------------------------------------------------------------------------------
/12 - SSR pt1 (Deprecated)/src/server/index.js:
--------------------------------------------------------------------------------
1 | import express from "express";
2 | import React from "react";
3 | import { renderToString } from "react-dom/server";
4 | import App from "../shared/App";
5 |
6 | const app = express();
7 |
8 | app.use(express.static("public"));
9 |
10 | app.get("*", (req, res) => {
11 | res.send(`
12 |
13 |
14 | Universal Reacl
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |