├── .gitignore
├── README.md
├── package.json
├── public
├── favicon.ico
├── index.html
└── manifest.json
└── src
├── App.css
├── App.js
├── App.test.js
├── components
├── cartTotal.jsx
├── product.jsx
└── products.jsx
├── index.css
├── index.js
├── logo.svg
└── serviceWorker.js
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 |
21 | npm-debug.log*
22 | yarn-debug.log*
23 | yarn-error.log*
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Quick refresher notes for React.js
2 |
3 | This repository contains notes and the code for the brilliant [React.js crash course by Mosh Hamedani](https://www.youtube.com/watch?v=Ke90Tje7VS0).
4 |
5 | ### Libraries used
6 |
7 | - create-react-app@1.5.2
8 | - bootstrap@4.1.1
9 |
10 | ### Setup
11 |
12 | - Install VS Code
13 | - Helpful extensions
14 | - Prettier by Esben Petersen
15 | - Simple React Snippets by Burke Holland
16 | - Install bootstrap
17 | - VS Code theme : Ayu Mirage
18 |
19 | ### Useful VS Code shortcuts (Mac)
20 |
21 | - command+d after selecting text to edit all occurences with multiple cursors.
22 | - ctrl+shift+R after selecting a few lines to move those into a new function.
23 |
24 | ### React basics
25 |
26 | - React components have some state (data) and render function (to render data).
27 | - Render function uses JSX.
28 | - Render function creates/outputs React elements.
29 | - React elements are JS objects and in-memory representation of actual DOM elements.
30 | - One-to-one mapping between react elements and DOM elements.
31 | - A tree of react elements is virtual DOM.
32 | - React diffs old virtual DOM (or old react element) with new virtual DOM (or new react element) and applies only the difference to the actual DOM tree.
33 | - Virtual DOM is cheap to construct.
34 | - One root component called App in every react application and every other component is a child component of this App component.
35 | - App.js will contain App class component.
36 | - index.js will contain ReactDOM.render(``, document.getElementById("root"));
37 | - App should be imported in index.js.
38 | - let vs const. Use const if not modifying.
39 | - Apply classes to elements using className attribute since class is a reserved keyword in JS.
40 | - Import React from 'react' because return of render function is converted to plain javascript by Babel wherein react elements are converted to React.createElement so we are not using react directly but indirectly.
41 | - No need of curly braces around object names in import statement if it is the default export from that module ('React' in import React from 'react').
42 |
43 | ### JSX
44 |
45 | - The JSX returned by render function must have only one parent element because the first argument to React.createElement takes in type of the element and Babel won't know the type if multiple elements exist alongside with no parent like `
`.
46 | - JSX expressions are compiled to react elements.
47 | - So return this from render function: one parent element with as many child elements put in parenthesis because in JS multi-line return stmt is read properly only with parenthesis otherwise JS assumes return terminates after first line and adds semi-colon automatically.
48 | - Use React.fragment as parent div in above note to avoid a div that doesn't do anything.
49 | - JSX expressions are like normal JS objects. You can return them from a fn, pass them to a fn, use as value of a const or variable.
50 | - JSX is not a templating engine so no ngFor like it is in Angular.
51 | - In return stmt within render fn, you can add plain JS in curly braces {}.
52 |
53 | ### Rendering Lists
54 |
55 | - There should be a "key" attribute in `
` to help react decide what's changed which is unique to each list element. Or 'key' attribute in every react element that's rendered dynamically using a 'map' for each element in a collection.
56 |
57 | ### Styling
58 |
59 | - Use "styles" attribute for custom styling. Define a property or an object where keys are camelcased css properties with values.
60 | - Or use inline styles where you put that object inline.
61 |
62 | ### Conditional rendering
63 |
64 | - No ngIf like in angular because JSX is not a templating engine.
65 | - One way: Call a { function } inside render method. Make that function use regular JS to check for conditions and return JSX for different conditions.
66 | - Another way: { condition `&&` `` }
67 |
68 | ### Event handling
69 |
70 | - Functions in JS are objects so they have properties and methods which can be accessed.
71 | - Use bind method to bind the function object to the current instance of the class object 'this' : this.handleIncrement = this.handleIncrement.bind(this).
72 | - If we write a constructor for a class then we need to first call the constructor of the parent class using super().
73 | - This will require us to call super and bind methods for every event handler function using a constructor.
74 | - Better solution: Use arrow function!
75 | - Arrow function dont re-bind the this keyword, they inherit it.
76 | - Change event handler functions to arrow functions.
77 |
78 | ### Updating the state
79 |
80 | - React only understands state changes if they are done using setState. setState is inherited from the base Component class. Angular doesnt need this because it automatically detects changes because all browser events are monkey patched. So button clicks or inputs notifies Angular which triggers change detection algos and updates the view.
81 | - setState takes an object. All key-value pairs in this objects are merged with the existing state. If a key exists, it is overwritten.
82 |
83 | ### What happens when state changes
84 |
85 | - Whenever setState is seen, React will schedule a call to the render method. An async call. No fixed time. It created a new virtual DOM tree which is compared with the old tree and the diff is applied to the real DOM.
86 |
87 | ### Passing arguments to event handlers
88 |
89 | - Whenever we need to pass args to event handlers (arrow fns which are called in onClick), call an arrow fn whose body will contain a call to the actual event handler.
90 |
91 | ```javascript
92 | onClick={ () => this.handleClick(product) }
93 | ```
94 |
95 | ### Composing components
96 |
97 | - Every react component has a property called prop.
98 | - Prop is a plain JS object. It includes all the attributes that we use when using a component (attribute=value passed when using ``).
99 | - 'Key' will not be part of props since it is a special attribute to uniquely identify objects.
100 | - When we use a component and enclose many other react elements within the component, all of these elements are accessed using this.props.children.
101 |
102 | ```
103 |
104 | ```
105 |
106 | - this.props.children will contain ``.
107 | - Better idea: just pass data represented by children as props and create children elements in the component itself.
108 |
109 | ### Debugging react applications
110 |
111 | - Use react developer tools.
112 |
113 | ### props vs state
114 |
115 | - Props includes data that we give to a component.
116 | - State includes data that is local or private to that component.
117 | - Other components cannot access other component's state.
118 | - Props is read-only. we cannot change the input passed to a component from inside of that component.
119 | - But if there is need to change the input then put that in the state of that component first and then change it in one of the lifecycle methods.
120 |
121 | ### raising and handling events
122 |
123 | - Very important rule of thumb in React:
124 | A component that owns a piece of the state should be the one modifying it.
125 | - So if you want to update some piece of state in the parent component via an action (like clicking a button in child component) then raise an event from the child component that is passed to parent where that event is handled.
126 | - How to implement? Add new method in parent to and pass a reference to that method via props to the child component.
127 |
128 | ### Single source of truth
129 |
130 | - Let's say the data in the state of parent is passed to a child via props but the child has it's local state. This local state needs to be updated everytime the parent changes its own data that was passed via props. The child's view won't change because this view uses local state that wasn't updated.
131 | - To avoid this we just make the child a controlled component.
132 |
133 | ### Controlled component
134 |
135 | - A Controlled component doesn't have a local state. It receives all the data via props and raises events to change that event. It is entirely controlled by its parent.
136 |
137 | ### Keep components in sync/ Lifting state up
138 |
139 | - If there is some state that is shared between a parent and child but a new sibling of the parent comes in which wants that state as well, then lift the state up. Create a new parent for the existing parent and the sibling and pass the state down to these two from the one single parent.
140 |
141 | ### Stateless Functional Components
142 |
143 | - If a component doesnt have a state of its own and all it does is to print some data that it receives via props to the UI then we can convert that class to a function which is called a Stateless Functional Component.
144 | - So instead of having a class which extends Component class and has a render method we simply create a const which is an arrow function and returns JSX.
145 | - this.props only works in class components. we need to remove 'this' and accept 'props' as an argument to the arrow function and use it directly. React will pass props as arg to this function at runtime.
146 |
147 | ### Lifecycle Hooks
148 |
149 | - Lifecycle hooks allow us to hook into certain moments during lifecycle of a component
150 | - First phase: Mounting phase. This is when an instance of component is created and inserted into DOM.
151 | - Mounting phase: 3 hooks - constructor, render, componentDidMount. Called in order by React.
152 | - Second phase: Update phase - happens when state or props of a component get changed.
153 | - Update phase: 2 hooks - render, componentDidUpdate.
154 | - Third phase: UnMounting phase - happens just before a component is removed from DOM.
155 | - UnMounting phase: 1 hook - componentWillUnMount
156 | - Other hooks present but rarely used.
157 | - We cannot use lifecycle methods in stateless functional components.
158 |
159 | Common use cases
160 |
161 | - constructor: initial properties and state based on props we receive from outside.
162 | - cannot use setState in construcor because it can only be called once the component is rendered and placed in the DOM.
163 | - render: when a component is rendered all its children components are rendered recursively.
164 | - componentDidMount: make AJAX calls. setState can be used and assigned data from ajax call.
165 | - componentDidUpdate: called when there is a state or props change. Called with two args: prevProps, prevState. Make conditional ajax calls if needed based on difference between prevProps and props (current).
166 | - componentWillUnMount: called just before a component is removed from DOM. Allows us to do any kind of cleanup. Good place to avoid memory leaks.
167 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "shopping-cart",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "react": "^16.6.3",
7 | "react-dom": "^16.6.3",
8 | "react-scripts": "2.1.1"
9 | },
10 | "scripts": {
11 | "start": "react-scripts start",
12 | "build": "react-scripts build",
13 | "test": "react-scripts test",
14 | "eject": "react-scripts eject"
15 | },
16 | "eslintConfig": {
17 | "extends": "react-app"
18 | },
19 | "browserslist": [
20 | ">0.2%",
21 | "not dead",
22 | "not ie <= 11",
23 | "not op_mini all"
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/amitnavindgi/react-shopping-cart-demo/e9df3c98ae97505e89ecf983681c6417ef322166/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
22 | React App
23 |
24 |
25 |
28 |
29 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 40vmin;
8 | }
9 |
10 | .App-header {
11 | background-color: #282c34;
12 | min-height: 100vh;
13 | display: flex;
14 | flex-direction: column;
15 | align-items: center;
16 | justify-content: center;
17 | font-size: calc(10px + 2vmin);
18 | color: white;
19 | }
20 |
21 | .App-link {
22 | color: #61dafb;
23 | }
24 |
25 | @keyframes App-logo-spin {
26 | from {
27 | transform: rotate(0deg);
28 | }
29 | to {
30 | transform: rotate(360deg);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from "react";
2 | import "./App.css";
3 | import Products from "./components/products";
4 | import CartTotal from "./components/cartTotal";
5 |
6 | class App extends Component {
7 | state = {
8 | products: [
9 | { id: 1, count: 0 },
10 | { id: 2, count: 2 },
11 | { id: 3, count: 0 },
12 | { id: 4, count: 0 }
13 | ]
14 | };
15 |
16 | constructor() {
17 | // must call parent constructor first
18 | super();
19 | // called 1st during mounting phase
20 | console.log("App - constructor");
21 | }
22 |
23 | componentDidMount() {
24 | // good place to make ajax calls to fetch remote data
25 | // called 3rd in mounting phase
26 | console.log("App - componentDidMount");
27 | }
28 |
29 | componentDidUpdate() {
30 | // called during update phase along with render
31 | console.log("App - componentDidUpdate");
32 | }
33 |
34 | render() {
35 | // called 2nd in mounting phase
36 | console.log("App - render");
37 |
38 | return (
39 |
40 | );
41 | }
42 | }
43 |
44 | export default Products;
45 |
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | padding: 0;
4 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
5 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
6 | sans-serif;
7 | -webkit-font-smoothing: antialiased;
8 | -moz-osx-font-smoothing: grayscale;
9 | }
10 |
11 | code {
12 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
13 | monospace;
14 | }
15 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import "./index.css";
4 | import App from "./App";
5 | import * as serviceWorker from "./serviceWorker";
6 |
7 | import "bootstrap/dist/css/bootstrap.css";
8 |
9 | ReactDOM.render(, document.getElementById("root"));
10 |
11 | // If you want your app to work offline and load faster, you can change
12 | // unregister() to register() below. Note this comes with some pitfalls.
13 | // Learn more about service workers: http://bit.ly/CRA-PWA
14 | serviceWorker.unregister();
15 |
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read http://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.1/8 is considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit http://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See http://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl)
104 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------