feat: restructure docs into "chapters" (#12)

* feat(docker, k8s): create containers folder and kubernetes notes
This commit is contained in:
Marcello 2023-03-13 11:33:51 +00:00
parent b1cb858508
commit 2725e3cb70
92 changed files with 777 additions and 367 deletions

View file

@ -0,0 +1,112 @@
# AJAX
**AJAX**: Asynchronous JavaScript and XML
AJAX Interaction:
1. An event occurs in a web page (the page is loaded, a button is clicked)
2. 2.An `XMLHttpRequest` object is created by JavaScript
3. 3.The `XMLHttpRequest` object sends a request to a web server
4. 4.The server processes the request
5. 5.The server sends a response back to the web page
6. 6.The response is read by JavaScript
7. 7.Proper action (like page update) is performed by JavaScript
## XMLHttpRequest
```js
var request = new XMLHttpRequest();
request.addEventListener(event, function() {...});
request.open("HttpMethod", "path/to/api", true); // third parameter is asynchronicity (true = asynchronous)
request.setRequestHeader(key, value) // HTTP Request Headers
request.send()
```
To check the status use `XMLHttpRequest.status` and `XMLHttpRequest.statusText`.
### XMLHttpRequest Events
**loadstart**: fires when the process of loading data has begun. This event always fires first
**progress**: fires multiple times as data is being loaded, giving access to intermediate data
**error**: fires when loading has failed
**abort**: fires when data loading has been canceled by calling abort()
**load**: fires only when all data has been successfully read
**loadend**: fires when the object has finished transferring data always fires and will always fire after error, abort, or load
**timeout**: fires when progression is terminated due to preset time expiring
**readystatechange**: fires when the readyState attribute of a document has changed
**Alternative `XMLHttpRequest` using `onLoad`**:
```js
var request = new XMLHttpRequest();
request.open('GET', 'myservice/username?id=some-unique-id');
request.onload = function(){
if(request.status ===200){
console.log("User's name is "+ request.responseText);
} else {
console.log('Request failed. Returned status of '+ request.status);
}
};
request.send();
```
**Alternative `XMLHttpRequest` using `readyState`**:
```js
var request = new XMLHttpRequest(), method ='GET', url ='https://developer.mozilla.org/';
request.open(method, url, true);
request.onreadystatechange = function(){
if(request.readyState === XMLHttpRequest.DONE && request.status === 200){
console.log(request.responseText);
}
};
request.send();
```
`XMLHttpRequest.readyState` values:
`0` `UNSENT`: Client has been created. `open()` not called yet.
`1` `OPENED`: `open()` has been called.
`2` `HEADERS_RECEIVED`: `send()` has been called, and headers and status are available.
`3` `LOADING`: Downloading; `responseText` holds partial data.
`4` `DONE`: The operation is complete.
### `XMLHttpRequest` Browser compatibility
Old versions of IE don't implement XMLHttpRequest. You must use the ActiveXObject if XMLHttpRequest is not available
```js
var request =window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP');
// OR
var request;
if(window.XMLHttpRequest){
// code for modern browsers
request = new XMLHttpRequest();
} else {
// code for old IE browsers
request = new ActiveXObject('Microsoft.XMLHTTP');
}
```
## Status & Error Handling
Always inform the user when something is loading. Check the status and give feedback (a loader or message)
Errors and responses need to be handled. There is no guarantee that HTTP requests will always succeed.
### Cross Domain Policy
Cross domain requests have restrictions.
Examples of outcome for requests originating from: `http://store.company.com/dir/page.htmlCross-origin`
| URL | Outcome | Reason |
|-------------------------------------------------|---------|--------------------|
| `http://store.company.com/dir2/other.html` | success |
| `http://store.company.com/dir/inner/other.html` | success |
| `https://store.company.com/secure.html` | failure | Different protocol |
| `http://store.company.com:81/dir/other.html` | failure | Different port |
| `http://news.company.com/dir/other.html` | failure | Different host |

View file

@ -0,0 +1,164 @@
# Document Object Model (DOM)
The **Document Object Model** is a *map* of the HTML document. Elements in an HTML document can be accessed, changed, deleted, or added using the DOM.
The document object is *globally available* in the browser. It allows to access and manipulate the DOM of the current web page.
## DOM Access
### Selecting Nodes from the DOM
`getElementById()` and `querySelector()` return a single element.
`getElementsByClassName()`, `getElementsByTagName()`, and `querySelectorAll()` return a collection of elements.
```js
Javascript
// By Id
var node = document.getElementById('id');
// By Tag Name
var nodes = document.getElementsByTagName('tag');
// By Class Name
var nodes = document.getElementsByClassName('class');
// By CSS Query
var node = document.querySelector('css-selector');
var nodes = document.querySelectorAll('css-selector');
```
## Manipulating the DOM
### Manipulating a node's attributes
It's possible access and change the attributes of a DOM node using the *dot notation*.
```js
// Changing the src of an image:
var image = document.getElementById('id');
var oldImageSource = image.src;
image.src = 'image-url';
//Changing the className of a DOM node:
var node = document.getElementById('id');
node.className = 'new-class';
```
### Manipulating a node's style
It's possible to access and change the styles of a DOM nodes via the **style** property.
CSS property names with a `-` must be **camelCased** and number properties must have a unit.
```css
body {
color: red;
background-color: pink;
padding-top: 10px;
}
```
```js
var pageNode = document.body;
pageNode.style.color = 'red';
pageNode.style.backgroundColor = 'pink';
pageNode.style.paddingTop = '10px';
```
### Manipulating a node's contents
Each DOM node has an `innerHTML` attribute. It contains the HTML of all its children.
```js
var pageNode = document.body;
console.log(pageNode.innerHTML);
// Set innerHTML to replace the contents of the node:
pageNode.innerHTML = "<h1>Oh, no! Everything is gone!</h1>";
// Or add to innerHTML instead:
pageNode.innerHTML += "P.S. Please do write back.";
```
To change the actual text of a node, `textContent` may be a better choice:
`innerHTML`:
- Works in older browsers
- **More powerful**: can change code
- **Less secure**: allows cross-site scripting (XSS)
`textContent`:
- Doesn't work in IE8 and below
- **Faster**: the browser doesn't have to parse HTML
- **More secure**: won't execute code
### Reading Inputs From A Form
In `page.html`:
```html
<input type="" id="identifier" value="">
```
In `script.js`:
```js
var formNode = document.getElementById("Identifier");
var value = formNode.value;
```
## Creating & Removing DOM Nodes
The document object also allows to create new nodes from scratch.
```js
// create node
document.createElement('tagName');
document.createTextNode('text');
domNode.appendChild(childToAppend); // insert childTaAppend after domNode
// insert node before domNode
domNode.insertBefore(childToInsert, domnode);
domNode.parentNode.insertBefore(childToInsert, nodeAfterChild);
// remove a node
domNode.removeChild(childToRemove);
node.parentNode.removeChild(node);
```
Example:
```js
var body = document.body;
var newImg = document.createElement('img');
newImg.src = 'http://placekitten.com/400/300';
newImg.style.border = '1px solid black';
body.appendChild(newImg);
var newParagraph = document.createElement('p');
var newText = document.createTextNode('Squee!');
newParagraph.appendChild(newText);
body.appendChild(newParagraph);
```
### Creating DOM Nodes with Constructor Functions
```js
function Node(params) {
this.node = document.createElement("tag");
this.node.attribute = value;
// operations on the node
return this.node;
}
var node = Node(params);
domElement.appendChild(node);
```

View file

@ -0,0 +1,88 @@
# Events & Animation
## Events
Event Types:
- **Mouse Events**: `mousedown`, `mouseup`, `click`, `dbclick`, `mousemove`, `mouseover`, `mousewheel`, `mouseout`, `contextmenu`, ...
- **Touch Events**: `touchstart`, `touchmove`, `touchend`, `touchcancel`, ...
- **Keyboard Events**: `keydown`, `keypress`, `keyup`, ...
- **Form Events**: `focus`, `blur`, `change`, `submit`, ...
- **Window Events**: `scroll`, `resize`, `hashchange`, `load`, `unload`, ...
### Managing Event Listeners
```js
var domNode = document.getElementById("id");
var onEvent = function(event) { // parameter contains info on the triggered event
event.preventDefault(); // block execution of default action
// logic here
}
domNode.addEventListener(eventType, callback);
domNode.removeEventListener(eventType, callback);
```
### Bubbling & Capturing
Events in Javascript propagate through the DOM tree.
[Bubbling and Capturing](https://javascript.info/bubbling-and-capturing)
[What Is Event Bubbling in JavaScript? Event Propagation Explained](https://www.sitepoint.com/event-bubbling-javascript/)
### Dispatching Custom Events
Event Options:
- `bubbles` (bool): whether the event propagates through bubbling
- `cancellable` (bool): if `true` the "default action" may be prevented
```js
let event = new Event(type [,options]); // create the event, type can be custom
let event = new CustomEvent(type, { detail: /* custom data */ }); // create event w/ custom data
domNode.dispatchEvent(event); // launch the event
```
![Event Inheritance](../../img/javascript_event-inheritance.png)
## Animation
The window object is the assumed global object on a page.
Animation in JavascriptThe standard way to animate in JS is to use window methods.
It's possible to animate CSS styles to change size, transparency, position, color, etc.
```js
//Calls a function once after a delay
window.setTimeout(callbackFunction, delayMilliseconds);
//Calls a function repeatedly, with specified interval between each call
window.setInterval(callbackFunction, delayMilliseconds);
//To stop an animation store the timer into a variable and clear it
window.clearTimeout(timer);
window.clearInterval(timer);
// execute a callback at each frame
window.requestAnimationFrame(callbackFunction);
```
### Element Position & dimensions
[StackOverflow](https://stackoverflow.com/a/294273/8319610)
[Wrong dimensions at runtime](https://stackoverflow.com/a/46772849/8319610)
```js
> console.log(document.getElementById('id').getBoundingClientRect());
DOMRect {
bottom: 177,
height: 54.7,
left: 278.5,
right: 909.5,
top: 122.3,
width: 631,
x: 278.5,
y: 122.3,
}
```

View file

@ -0,0 +1,958 @@
# JavaScript
## Basics
### Notable javascript engines
- **Chromium**: `V8` from Google
- **Firefox**: `SpiderMonkey` from Mozilla
- **Safari**: `JavaScriptCore` from Apple
- **Internet Explorer**: `Chakra` from Microsoft
### Comments
```javascript
//single line comment
/*multiline comment*/
```
### File Header
```javascript
/**
* @file filename.js
* @author author's name
* purpose of file
*
* detailed explanation of what the file does on multiple lines
*/
```
### Modern Mode
If located at the top of the script the whole script works the “modern” way (enables post-ES5 functionalities).
```js
"use strict"
// script contents
```
### Pop-Up message
Interrupts script execution until closure, **to be avoided**
```javascript
alert("message");
```
### Print message to console
`console.log(value);`
## Variables
### Declaration & Initialization
[var vs let vs const](https://www.freecodecamp.org/news/var-let-and-const-whats-the-difference/)
Variable names can only contain numbers, digits, underscores and $. Variable names are camelCase.
`let`: Block-scoped; access to variable restricted to the nearest enclosing block.
`var`: Function-scoped
`let variable1 = value1, variable2 = value2;`
`var variable1 = value1, variable2 = value2;`
### Scope
Variable declared with `let` are in local to the code block in which are declared.
Variable declared with `var` are local only if declared in a function.
```js
function func(){
variable = value; // implicitly declared as a global variable
var variable = value; // local variable
}
var a = 10; // a is 10
let b = 10; // b is 10
{
var x = 2, a = 2; // a is 2
let y = 2, b = 2; // b is 2
}
// a is 2, b is 10
// x can NOT be used here
// y CAN be used here
```
### Constants
Hard-coded values are UPPERCASE and snake_case, camelCase otherwise.
`const CONSTANT = value;`
## Data Types
`Number`, `String`, `Boolean`, etc are *built-in global objects*. They are **not** types. **Do not use them for type checking**.
### Numeric data types
Only numeric type is `number`.
```javascript
let number = 10; //integer numbers
number = 15.7; //floating point numbers
number = Infinity; //mathematical infinity
number = - Infinity;
number = 1234567890123456789012345678901234567890n; //BigInt, value > 2^53, "n" at the end
number = "text" / 2; //NaN --> not a number.
```
[Rounding Decimals in JavaScript](https://www.jacklmoore.com/notes/rounding-in-javascript/)
[Decimal.js](https://github.com/MikeMcl/decimal.js)
Mathematical expression will *never* cause an error. At worst the result will be NaN.
### String data type
```javascript
let string = "text";
let string$ = 'text';
let string_ = `text ${expression}`; //string interpolation (needs backticks)
string.length; // length of the string
let char = string.charAt(index); // extraction of a single character by position
string[index]; // char extraction by property access
let index = string.indexOf(substring); // start index of substring in string
```
Property access is unpredictable:
- does not work in IE7 or earlier
- makes strings look like arrays (confusing)
- if no character is found, `[ ]` returns undefined, `charAt()` returns an empty string
- Is read only: `string[index] = "value"` does not work and gives no errors
### [Slice vs Substring vs Substr](https://stackoverflow.com/questions/2243824/what-is-the-difference-between-string-slice-and-string-substring)
If the parameters to slice are negative, they reference the string from the end. Substring and substr doesn´t.
```js
string.slice(begin [, end]);
string.substring(from [, to]);
string.substr(start [, length]);
```
### Boolean data type
```javascript
let boolean = true;
let boolean_ = false;
```
### Null data type
```javascript
let _ = null;
```
### Undefined
```javascript
let $; //value is "undefined"
$ = undefined;
```
### Typeof()
```javascript
typeof x; //returns the type of the variable x as a string
typeof(x); //returns the type of the variable x as a string
```
The result of typeof null is "object". That's wrong.
It is an officially recognized error in typeof, kept for compatibility. Of course, null is not an object.
It is a special value with a separate type of its own. So, again, this is an error in the language.
### Type Casting
```javascript
String(value); //converts value to string
Number(value); //converts value to a number
Number(undefined); //--> NaN
Number(null); //--> 0
Number(true); //--> 1
Number(false); //--> 0
Number(String); //Whitespace from the start and end is removed. If the remaining string is empty, the result is 0. Otherwise, the number is "read" from the string. An error gives NaN.
Boolean(value); //--> true
Boolean(0); //--> false
Boolean(""); //--> false
Boolean(null); //--> false
Boolean(undefined); //--> false
Boolean(NaN); //--> false
//numeric type checking the moronic way
typeof var_ == "number"; // typeof returns a string with the name of the type
```
### Type Checking
```js
isNaN(var); // converts var in number and then check if is NaN
Number("A") == NaN; //false ?!?
```
### Dangerous & Stupid Implicit Type Casting
```js
2 + 'text'; //"2text", implicit conversion and concatenation
1 + "1"; //"11", implicit conversion and concatenation
"1" + 1; //"11", implicit conversion and concatenation
+"1"; //1, implicit conversion
+"text"; // NaN
1 == "1"; //true
1 === "1"; //false
1 == true; //true
0 == false; //true
"" == false; //true
```
## Operators
| Operator | Operation |
| ------------ | --------------- |
| `(...)` | grouping |
| a`.`b | member access |
| `new` a(...) | object creation |
| a `in` b | membership |
### Mathematical Operators
| Operator | Operation |
| -------- | -------------- |
| a `+` b | addition |
| a `-` b | subtraction |
| a `*` b | multiplication |
| a `**` b | a^b |
| a `/` b | division |
| a `%` b | modulus |
### Unary Increment Operators
| Operator | Operation |
| ------------ | ----------------- |
| `--`variable | prefix decrement |
| `++`variable | prefix increment |
| variable`--` | postfix decrement |
| variable`++` | postfix increment |
### Logical Operators
| Operator | Operation |
| -------- | --------------- |
| a `&&` b | logical **AND** |
| a `||` b | logical **OR** |
| `!`a | logical **NOT** |
### Comparison Operators
| Operator | Operation |
| --------- | ------------------- |
| a `<` b | less than |
| a `<=` b | less or equal to |
| a `>` b | greater than |
| a `>=` b | greater or equal to |
| a `==` b | equality |
| a `!=` b | inequality |
| a `===` b | strict equality |
| a `!==` b | strict inequality |
### Bitwise Logical Operators
| Operator | Operation |
| --------- | ---------------------------- |
| a `&` b | bitwise AND |
| a `|` b | bitwise OR |
| a `^` b | bitwise XOR |
| `~`a | bitwise NOT |
| a `<<` b | bitwise left shift |
| a `>>` b | bitwise right shift |
| a `>>>` b | bitwise unsigned right shift |
### Compound Operators
| Operator | Operation |
| ---------- | ----------- |
| a `+=` b | a = a + b |
| a `-=` b | a = a - b |
| a `*=` b | a = a * b |
| a `**=` b | a = a ** b |
| a `/=` b | a = a / b |
| a `%=` b | a = a % b |
| a `<<=` b | a = a << b |
| a `>>=` b | a = a >> b |
| a `>>>=` b | a = a >>> b |
| a `&=` b | a = a & b |
| a `^=` b | a = a ^ b |
| a `|=` b | a = a ! b |
## Decision Statements
### IF-ELSE
```javascript
if (condition) {
//code here
} else {
//code here
}
```
### IF-ELSE Multi-Branch
```javascript
if (condition) {
//code here
} else if (condition) {
//code here
} else {
//code here
}
```
### Ternary Operator
`condition ? <expr1> : <expr2>;`
### Switch Statement
```javascript
switch (expression) {
case expression:
//code here
break;
default:
//code here
break;
}
```
## Loops
### While Loop
```javascript
while (condition) {
//code here
}
```
### Do-While Loop
```javascript
do {
//code here
} while (condition);
```
### For Loop
```javascript
// basic for
for (begin; condition; step) { }
for (var variable in iterable) { } // for/in statement loops through the properties of an object
for (let variable in iterable) { } // instantiate a new variable at each iteration
// for/of statement loops through the values of an iterable objects
// for/of lets you loop over data structures that are iterable such as Arrays, Strings, Maps, NodeLists, and more.
for (var variable of iterable) { }
for (let variable of iterable) { } // instantiate a new variable at each iteration
// foreach (similar to for..of)
iterable.forEach(() => { /* statements */ });
```
### Break & Continue statements
`break;` exits the loop.
`continue;` skip to next loop cycle.
```javascript
label: for(begin; condition; step) {
//code here
}
break label; //breaks labelled loop and nested loops inside it
```
## Arrays
```js
let array = []; // empty array
let array = ["text", 3.14, [1.41]]; // array declaration and initialization
array.length; // number of items in the array
array[index]; // access to item by index
array[index] = item; // change or add item by index
array.push(item); //add item to array
array.pop(); // remove and return last item
array.join("separator"); // construct a string from the items of the array, separated by SEPARATOR
array.find(item => condition); // returns the value of the first element in the provided array that satisfies the provided testing function
array.fill(value, start, end); // fills an array with the passed value
// https://stackoverflow.com/a/37601776
array.slice(start, end); // RETURN list of items between indexes start and end-1
array.splice(start, deleteCount, [items_to_add]); // remove and RETURN items from array, can append a list of items. IN PLACE operation
```
### `filter()` & `map()`, `reduce()`
```js
let array = [ items ];
// execute an operation on each item, producing a new array
array.map(function);
array.map(() => operation);
array.filter(() => condition); // return an items only if the condition is true
// execute a reducer function on each element of the array, resulting in single output value
array.reduce((x, y) => ...);
```
## Spread Operator (...)
```js
// arrays
let array1 = [ 1, 2, 3, 4, 5, 6 ];
let array2 = [ 7, 8, 9, 10 ];
let copy = [ ...array1 ]; // shallow copy
let copyAndAdd = [ 0, ...array1, 7 ]; // insert all values in new array
let merge = [ ...array1, ...array2 ]; // merge the arrays contents in new array
// objects
let obj = { prop1: value1, prop2: value2 };
let clone = { ...obj, prop: value }; // shallow copy, and update copy prop
let cloneAndAdd = { prop0: value0, ...obj, prop3: value3 };
// strings
let alphabet = "abcdefghijklmnopqrstxyz"
let letters = [ ...alphabet ]; // alphabet.split("")
//function arguments
let func = (arg1 = val1, arg2 = val2) => expression;
let args = [ value1, value2 ];
func(arg0, ...args);
```
## Dictionaries
```js
let dict = { FirstName: "Chris", "one": 1, 1: "some value" };
// add new or update property
dict["Age"] = 42;
// direct property by name
// because it's a dynamic language
dict.FirstName = "Chris";
```
### Iterating Key-Value pairs
```js
for(let key in dict) {
let value = dict[key];
// do something with "key" and "value" variables
}
Object.keys(dict).forEach(key => { });
```
## Functions
### JSDOC documentation standard
```javascript
/**
* @param {type} parameter - description
* @returns {type} parameter - description
* */
```
### Function Declaration
```javascript
// ...args will contain extra parameters (rest argument)
function functionName(parameter=default-value, ...args) {
//code here
return <expression>;
}
```
### Default Parameters (old versions)
```javascript
function functionName(parameters) {
if (parameter == undefined) {
parameter = value;
}
//code here
return <expression>;
}
```
### Function Expressions
```javascript
let functionName = function(parameters) {
//code here
return expression;
}
```
### Arrow Functions
```javascript
(input) => { /* statements */ }
(input) => expression;
input => expression; // parenthesis are optional
() => expression; // no parameters syntax
// variants
let func = (input) => {
// code here
};
let func = (input) => expression;
let func = input => expression;
func(); // function call
// return object literal
let func = (value) => ({property: value});
```
## Object Oriented Programming
An object is a collection of related data and/or functionality.
**Note**: It's not possible to transform a variable in an object simply by using the object assignment.
```js
let variable = value;
// object literal
let obj = {
property: value,
variable, // same as variable: variable
[property]: value // dynamic prop name
object: {
...
},
method: function() {
// code here
this.propertyName; // reference to object property inside the object
}
method; () => {
obj.propertyName; // this is undefined here, use full object name
}
};
// access to property (non existant properties will return Undefined)
obj.property; // dot notation
obj["property"]; // array notation
// property modification (will add property if missing)
obj.property = value; // dot notation
obj["property"] = value; // array notation
obj.func(); //method access
delete obj.propertyName; // delete property
Object.keys(obj); // list of all property names
Object.entries(obj); // list contents as key-value pairs
```
### Constructors and object instances
JavaScript uses special functions called **constructor functions** to define and initialize objects and their features.
Notice that it has all the features you'd expect in a function, although it doesn't return anything or explicitly create an object — it basically just defines properties and methods.
```js
// constructor function definition
function Class(params) {
this.property = param;
this.method = function(params) { /* code here */ }
}
let obj = new Class(params); // object instantiation
let obj = new Object(); // creates empty object
let obj = new Object({
// JSON
});
```
### Prototypes
Prototypes are the mechanism by which JavaScript objects *inherit* features from one another.
JavaScript is often described as a **prototype-based language**; to provide inheritance, objects can have a prototype object, which acts as a template object that it inherits methods and properties from.
An object's prototype object may also have a prototype object, which it inherits methods and properties from, and so on.
This is often referred to as a **prototype chain**, and explains why different objects have properties and methods defined on other objects available to them.
If a method is implemented on an object (and not it's prototype) then only that object will heve that method and not all the ones that come from the same prototype.
```js
// constructor function
function Obj(param1, ...) {
this.param1 = param1,
...
}
// method on the object
Obj.prototype.method = function(params) {
// code here (operate w/ this)
}
let obj = new Obj(args); // object instantiation
obj.method(); // call method from prototype
```
### Extending with prototypes
```js
// constructor function
function DerivedObj(param1, param2, ...) {
Obj.call(this, param1); // use prototype constructor
this.param2 = param2;
}
// extend Obj
DerivedObj.prototype = Object.create(Obj.prototype);
// method on object
DerivedObj.prototype.method = function() {
// code here (operate w/ this)
}
let dobj = new DerivedObj(args); // object instantiation
dobj.method(); // call method from prototype
```
### Classes (ES6+)
```js
class Obj {
constructor(param1, ...) {
this.param1 = param1,
...
}
get param1() // getter
{
return this.param1;
}
func() {
// code here (operate w/ this)
}
static func() { } // static method
// object instantiation
let obj = new Obj(param1, ...);
obj.func(); // call method
```
### Extending with Classes
```js
class DerivedObj extends Obj {
constructor(param1, param2, ...){
super(param1); // use superclass constructor
this.param2 = param2;
}
newFunc() { }
}
let dobj = DerivedObj();
dobj.newFunc();
```
## Deconstruction
### Object deconstruction
```js
let obj = {
property: value,
...
}
let { var1, var2 } = obj; // extract values from object into variables
let { property: var1, property2 : var2 } = obj; // extract props in variables w/ specified names
let { property: var1, var2 = default_value } = obj; // use default values if object has less then expected props
```
### Array Deconstruction
```js
let array = [ 1, 2, 3, 4, 5, 6 ];
let [first, , third, , seventh = "missing" ] = array; // extract specific values from array
```
## Serialization
```js
let object = {
// object attributes
}
let json = JSON.stringify(object); // serialize object in JSON
let json = { /* JSON */ };
let object = JSON.parse(json); // deserialize to Object
```
## Timing
### Timers
Function runs *once* after an interval of time.
```js
// param1, param2, ... are the arguments passed to the function (IE9+)
let timerId = setTimeout(func [, milliseconds, param1, param2, ... ]); // wait milliseconds before executing the code (params are read at execution time)
// works in IE9
let timerId = setTimeout(function(){
func(param1, param2);
}, milliseconds);
// Anonymous functions with arguments
let timerId = setTimeout(function(arg1, ...){
// code here
}, milliseconds, param1, ...);
clearTimeout(timerId) // cancel execution
// example of multiple consecutive schedules
let list = [1 , 2, 3, 4, 5, 6, 7, 8, 9, 10, "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", -1, -2, -3, -4, -5, -6, -7, -8, -9, -10]
function useTimeout(pos=0) {
setTimeout(function(){
console.log(list[pos]);
pos += 1; // update value for next call
if (pos < list.length) { // recursion exit condition
useTimeout(pos); // schedule next call with new value
}
}, 1_000, pos);
}
useTimeout();
```
### `let` vs `var` with `setTimeout`
```js
// let instantiates a new variable for each iteration
for (let i = 0; i < 3; ++i) {
setTimeout(function() {
console.log(i);
}, i * 100);
}
// output: 0, 1, 2
for (var i = 0; i < 3; ++i) {
setTimeout(function() {
console.log(i);
}, i * 100);
}
// output: 3, 3, 3
```
### Preserving the context
```js
let obj = {
prop: value,
method1 : function() { /* statement */ }
method2 : function() {
let self = this // memorize context inside method (otherwise callback will not know it)
setTimeout(function() { /* code here (uses self) */ })
}
}
// better
let obj = {
prop: value,
method1 : function() { /* statement */ }
method2 : function() {
setTimeout(() => { /* code here (uses this) */ }) // arrow func does not create new scope, this context preserved
}
}
```
### Intervals
Function runs regularly with a specified interval. JavaScript is **Single Threaded**.
```js
// param1, param2, ... are the arguments passed to the function (IE9+)
let timerId = setInterval(func, milliseconds [, param1, param2, ... ]); // (params are read at execution time)
// works in IE9
let timerId = setInterval(function(){
func(param1, param2);
}, milliseconds);
// Anonymous functions with arguments
let timerId = setInterval(function(arg1, ...){
// code here
}, milliseconds, param1, ...);
clearTimeout(timerId); // cancel execution
```
## DateTime
A date consists of a year, a month, a day, an hour, a minute, a second, and milliseconds.
There are generally 4 types of JavaScript date input formats:
- **ISO Date**: `"2015-03-25"`
- Short Date: `"03/25/2015"`
- Long Date: `"Mar 25 2015"` or `"25 Mar 2015"`
- Full Date: `"Wednesday March 25 2015"`
```js
// constructors
new Date();
new Date(milliseconds);
new Date(dateString);
new Date(year, month, day, hours, minutes, seconds, milliseconds);
// accepts parameters similar to the Date constructor, but treats them as UTC. It returns the number of milliseconds since January 1, 1970, 00:00:00 UTC.
Date.UTC(year, month, day, hours, minutes, seconds, milliseconds);
//static methods
Date.now(); // returns the number of milliseconds elapsed since January 1, 1970 00:00:00 UTC.
// methods
let date = new Date();
date.toSting(); // returns a string representing the specified Date object
date.toUTCString();
date.toDateString();
date.toTimeString(); // method returns the time portion of a Date object in human readable form in American English.
// get date
dare.getMonth();
date.getMinutes();
date.getFullYear();
// set date
date.setFullYear(2020, 0, 14);
date.setDate(date.getDate() + 50);
// parse valid dates
let msec = Date.parse("March 21, 2012");
let date = new Date(msec);
```
### Comparing Dates
Comparison operators work also on dates
```js
let date1 = new Date();
let date2 = new Date("May 24, 2017 10:50:00");
if(date1 > date2){
console.log('break time');
} else {
console.log('stay in class');
}
```
## [Exports](https://developer.mozilla.org/en-US/docs/web/javascript/reference/statements/export)
[Firefox CORS not HTTP](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSRequestNotHttp)
> **Note**: Firefox 68 and later define the origin of a page opened using a `file:///` URI as unique. Therefore, other resources in the same directory or its subdirectories no longer satisfy the CORS same-origin rule. This new behavior is enabled by default using the `privacy.file_unique_origin` preference.
```json
"privacy.file_unique_origin": "false"
```
In `page.html`
```html
<script src="scripts/module.js"></script>
<script src="scripts/script.js"></script>
```
In `module.js`:
```js
// exporting individual fractures
export default function() {} // one per module
export func = () => expression; // zero or more per module
// Export list
export { name1, name2, …, nameN };
// Renaming exports
export { variable1 as name1, variable2 as name2, …, nameN };
// Exporting destructured assignments with renaming
export const { name1, name2: bar } = o;
// re-export
export { func } from "other_script.js"
```
In `script.js`:
```js
import default_func_alias, { func as alias } from "./module.js"; // import default and set alias
import { default as default_func_alias, func as alias } from "./module.js"; // import default and set alias
// use imported functions
default_func_alias();
alias();
```
```js
import * from "./module.js"; // import all
module.function(); // use imported content with fully qualified name
```

View file

@ -0,0 +1,220 @@
# jQuery Library
## Including jQuery
### Download and link the file
```html
<head>
<script src="jquery-x.x.x.min.js"></script>
</head>
```
### Use a CDN
```html
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/x.x.x/jquery.min.js"></script>
</head>
<!-- OR -->
<head>
<script src="https://ajax.aspnetcdn.com/ajax/jQuery/jquery-x.x.x.min.js"></script>
</head>
```
### What is a CDN
A **content delivery network** or **content distribution network** (CDN) is a large distributed system of servers deployed in multiple data centers across the Internet.
The goal of a CDN is to serve content to end-users with high availability and high performance.
CDNs serve a large fraction of the Internet content today, including web objects (text, graphics and scripts), downloadable objects (media files, software, documents), applications (e-commerce, portals), live streaming media, on-demand streaming media, and social networks.
## HTML Manipulation
### [Finding DOM elements](https://api.jquery.com/category/selectors/)
```js
$('tag');
$("#id");
$(".class");
```
### Manipulating DOM elements
```js
$("p").addClass("special");
```
```html
<!-- before -->
<p>Welcome to jQuery<p>
<!-- after -->
<p class="special">Welcome to jQuery<p>
```
### Reading Elements
```html
<a id="yahoo" href="http://www.yahoo.com" style="font-size:20px;">Yahoo!</a>
```
```js
// find it & store it
var link = $('a#yahoo');
// get info about it
link.html(); // 'Yahoo!'
link.attr('href'); // 'http://www.yahoo.com'
link.css('font-size'); // '20px
```
### Modifying Elements
```js
// jQuery
$('a').html('Yahoo!');
$('a').attr('href', 'http://www.yahoo.com');
$('a').css({'color': 'purple'});
```
```html
<!-- before -->
<a href="http://www.google.com">Google</a>
<!-- after -->
<a href="http://www.yahoo.com" style="color:purple">Yahoo</a>
```
### Create, Store, Manipulate and inject
```js
let paragraph = $('<p class="intro">Welcome<p>'); // create and store element
paragraph.css('property', 'value'); // manipulate element
$("body").append(paragraph); // inject in DOM
```
### Regular DOM Nodes to jQuery Objects
```js
var paragraphs = $('p'); // an array
var aParagraph = paragraphs[0]; // a regular DOM node
var $aParagraph = $(paragraphs[0]); // a jQuery Object
// can also use loops
for(var i = 0; i < paragraphs.length; i++) {
var element = paragraphs[i];
var paragraph = $(element);
paragraph.html(paragraph.html() + ' WOW!');
}
```
## [Events](https://api.jquery.com/category/events/)
```js
var onButtonClick = function() {
console.log('clicked!');
}
// with named callback & .on
$('button').on('click', onButtonClick);
// with anonymous callback & .on
$('button').on('click', function(){
console.log('clicked!');
});
// with .click & named callback
$('button').click(onButtonClick);
```
### Preventing Default Event
```js
$('selector').on('event', function(event) {
event.preventDefault();
// custom logic
});
```
## Plugins
In the HTML, add a `<script>` ag that hotlinks to the CDN or source file:
```html
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"><script>
```
In the JavaScript call the jQuery plugin on the DOM:
```js
$("form").validate();
```
> **Note**: always link to the [minified](https://developers.google.com/speed/docs/insights/MinifyResources) js files.
## More jQuery
### Patters & Anti-Patterns
```js
// Pattern: name variables with $var
$myVar =$('#myNode');
// Pattern: store references to callback functions
var callback = function(argument){
// do something cool
};
$(document).on('click', 'p', myCallback);
// Anti-pattern: anonymous functions
$(document).on('click', 'p', function(argument){
// do something anonymous
});
```
### Chaining
```js
banner.css('color', 'red');
banner.html('Welcome!');
banner.show();
// same as:
banner.css('color', 'red').html('Welcome!').show();
// same as:
banner.css('color', 'red')
.html('Welcome!')
.show();
```
### DOM Readiness
DOM manipulation and event binding doesn't work if the `<script>` is in the `<head>`
```js
$(document).ready(function() {
// the DOM is fully loaded
});
$(window).on('load', function(){
// the DOM and all assets (including images) are loaded
});
```
## AJAX (jQuery `1.5`+)
```js
$.ajax({
method: 'POST',
url: 'some.php',
data: { name: 'John', location: 'Boston'}
})
.done(function(msg){alert('Data Saved: '+ msg);})
.fail(function(jqXHR, textStatus){alert('Request failed: '+ textStatus);});
```

View file

@ -0,0 +1,103 @@
# [React Router](https://reactrouter.com)
Popular routing library. Allows to specify a route through React components, declaring which component is to be loaded for a given URL.
Key Components:
- **Router**: wrap the app entry-point, usually `BrowserRouter`
- **Route**: "Load this component for this URL"
- **Link**: react-managed anchors that won't post back to the browser
## Routers
Router Types:
- *HashRouter*: `#route`, adds hashes to the URLs
- *BrowserRouter*: `/route`, uses HTML5 history API to provide clean URLs
- *MemoryRouter*: no URL
```js
// index.js
//other imports ...
import { BrowserRouter as Router } from "react-router-dom";
React.render(
<Router>
<App />
</Router>,
document.getElementById("DomID");
)
```
```js
// Component.js
import { Route, Route } from "react-router-dom";
<div>
{/* match route pattern exactly, all sub-routes will be matched otherwise */}
<Route path="/" exact element={<Component props={props} />} />
<Route path="/route" element={<Component props={props} />} />
...
</div>
// only one child can match, similar to Route-case
<Routes>
<Route path="/" exact element={<Component props={props} />} />
<Route path="/route" element={<Component props={props} />} />
<Route component={PageNotFound} /> {/* matches all non-existent URLs */}
</Route>
```
### URL Parameters & Query String
```js
// Given
<Route path="/route/:placeholder" element={<Component props={props} />} />
// URL: app.com/route/sub-route?param=value
function Component(props) {
props.match.params.placeholder; // sub-route
props.location.query; // { param: value }
props.location.pathname; // /route/sub-route?param=value
}
```
### Redirecting
```js
import { Navigate } from "react-router-dom";
// redirects to another URL on render, shouldn't be rendered on component mount but after an action
<Navigate to="/route" />
<Navigate from="/old-route" to="/new-route" />
{ condition && <Navigate to="/route" /> } // redirect if condition is true
// or redirect manipulating the history (always in props)
props.history.push("/new-route");
```
### Prompts
```js
import { Prompt } from "react-router-dom";
// displays a prompt when the condition is true
<Prompt when={condition} message="prompt message" />
```
## Link
Clicks on a link created with React-Router will be captured by react an all the routing will happen client side.
```js
import { Link } from "react-router-dom";
// TARGET: <Route path="/route/:itemId" />
<Link to="/route/1">Text</Link>
// add styling attributes to the rendered element when it matches the current URL.
<NavLink to="/route" exact activeClassName="class">Text</NavLink>
<NavLink to="/route" activeStyle={ { cssProp: value } }>Text</NavLink>
```

View file

@ -0,0 +1,150 @@
# Testing React
## [Jest](https://jestjs.io/)
### Jest Configuration
```js
// jest.config.js
module.exports = {
testEnvironment: 'jsdom',
moduleFileExtensions: ['js', 'jsx', 'ts', 'tsx', 'json', 'node'],
setupFilesAfterEnv: ['@testing-library/jest-dom/extend-expect'], // add testing-library methods to expect()
transform: { '^.+\\.tsx?$': 'ts-jest'} // use ts-jest fo ts files
}
```
### Jest Tests
[Expect docs](https://jestjs.io/docs/expect)
```js
// .spec.js or .test.js
it("test description", () => {
// test body
expect(expected).toEqual(actual);
});
// group related tests
describe("test group name", () => {
it(/* ... */);
it(/* ... */);
});
```
### Snapshots
In `Component.Snapshots.js`:
```js
import React from "react";
import renderer from "react-test-renderer";
import Component from "./path/to/Component";
// import mock data if necessary
it("test description", () => {
// renders the DOM tree of the component
const tree = renderer.create(<Component funcProp={jest.fn() /* mock function */} /* component props */ />);
// save a snapshot of the component at this point in time ( in __snapshots__ folder)
// in future test it will be checked to avoid regressions
// can be updated during jest --watch pressing "u"
expect(tree).matchSnapshot();
});
```
---
## [Enzyme](https://enzymejs.github.io/enzyme/)
### Enzyme Configuration
```js
// testSetup.js
import { configure } from "enzyme";
import Adapter from "enzyme-adapter-react-<version>";
configure({ adapter: new Adapter() });
```
### Enzyme Tests
In `Component.test.js`:
```js
import React from "react";
import { shallow, mount } from "enzyme";
// eventual wrapper components (react-router, react-redux's provider, ...) for mount render
// shallow renders single component w/o children, no DOM generated
// mount renders component w/ it's children
import Component from "./path/to/Component";
// factory to setup shallow test easily
function testHelper(args) {
const defaultProps = { /* default value for props in each test */ };
const props = { ...defaultProps, ...args };
return shallow(<Component {...props} />);
}
// shallow rendering test
it("test description", () => {
const dom = testHelper(/* optional args */);
// or
const dom = shallow(<Component /* props */ />);
// check a property of expected component
// selector can be from raw JSX (name of a component)
expect(dom.find("selector").property).toBe(expected);
});
// mount rendering test
if("test description" () => {
const dom = mount(
<WrapperComponent>
<Component /* props *//>
</WrapperComponent>
);
// selector has to be HTML selector since the component is rendered completely
// possible to test child components
expect(dom.find("selector").property).toBe(expected);
});
```
---
## [React Testing Library](https://testing-library.com/docs/react-testing-library/intro/)
Encourages to write test based on what the user sees. So components are always *mounted* and fully rendered.
### React Testing Library Tests
In `Components.test.js`:
```js
import React from "react";
import { cleanup, render } from "@testing-library/react";
import Component from "./path/to/Component";
afterEach(cleanup);
// factory to setup test easily
function testHelper(args) {
const defaultProps = { /* default value for props in each test */ };
const props = { ...defaultProps, ...args };
return render(<Component {...props} />);
}
it("test description", () => {
const { getByText } = testHelper();
// react testing library func
getByText("text"); // check if test is present in the rendered component
});
```

View file

@ -0,0 +1,261 @@
# React
## Components
There are two types of react components:
- Function Components
- Class Components
Both types can be stateful and have side effects or be purely presentational.
```jsx
// functional component
const Component = (props) => {
return (
<domElementOrComponent... />
);
}
// class component
class Component extends React.Component {
return (
<domElementOrComponent... />
);
}
```
*NOTE*: a component name *must* start with an uppercase letter.
Every components has two inputs: *props* and *state*. The props input is explicit while the state is implicit.
State is used to determine the changes and when to re-render.
Within the component state can be changed while the props object represent fixed input values.
JSX syntax can represent HTML but gets converted to pure JavaScript before being sent to the browser:
```js
// JSX
const element = (
<h1 className="greeting">Hello, world!</h1>
);
// compiled JS shipped to browser
const element = React.createElement(
'h1', // HTML tag name
{className: 'greeting'}, // attrs as JSON
'Hello, world!' // tag content (can be nested component)
);
```
### App Entry-point
```js
const container = document.getElementById('root')!;
const root = createRoot(container);
const element = <h1s>Hello World</h1>
root.render(element)
```
### Dynamic Expressions
```js
<tag>{expression}</tag> // expression is evaluated an it's result is displayed
<tag onEvent={funcReference}>{expression}</tag>
<tag onEvent={() => func(args)}>{expression}</tag>
```
### Props
```js
<Component propName={value} /> // pass a value the component
<Component propName={funcReference} /> // pass a function to the component
function Component(props) {
// use props with {props.propName}
}
class Component extends React.Component{
// use props with {this.props.propName}
render()
}
```
### Simple Function Component
```js
// Button.js
import { useState } from "react";
function Button() {
const [count, setCount] = useState(0); // hook
const handleCLick = () => setCount(count + 1); // logic
// JSX
return (
<button onClick={handleCLick}>
{count}
</button>
);
}
export default Button;
```
### Simple Class Component
```js
class Button extends React.Component {
state = {count: 0};
//or
constructor(props) {
super(props);
this.state = {count: 0};
}
componentDidMount() {} // called on successful component mount
handleClick = () => {
this.setState({ count: this.state.count + 1 });
}
// or
handleClick = () => {
this.setState((state, props) => ({ count: state.count + props.increment }) );
}
render(){
return (
<button onClick={this.handleClick}>
{this.state.count}
</button>
);
}
}
```
### Nesting Components
```js
import { useState } from "react";
function Button(props) {
return (
<button onClick={props.onClickFunc}>
+1
</button>
);
}
function Display (props) {
return (
<div>{props.message}</div>
);
}
function App() {
// state must be declare in the outer component it can be passed to each children
const [count, setCount] = useState(0);
const incrementCounter = () => setCount(count + 1);
return (
<div className="App">
<Button onClickFunc={incrementCounter}/>
<Display message={count}/>
</div>
);
}
export default App;
```
### User Input (Forms)
```js
function Form() {
const [userName, setUserName] = useState("");
handleSubmit = (event) => {
event.preventDefault();
// ...
}
return(
<form onSubmit={handleSubmit}>
<input
type="text"
value={userName} // controlled component
onChange={(event) => setUserName(event.target.value)} // needed to update UI on dom change
required
/>
<button></button>
</form>
);
}
```
### Lists of Components
```js
// ...
<div>
{array.map(item => <Component key={uniqueID}>)}
</div>
// ...
```
> **Note**: The `key` attribute of the component is needed to identify a particular item. It's most useful if the list has to be sorted.
## Hooks
### `useState`
Hook used to create a state object.
`useState()` results:
- state object (getter)
- updater function (setter)
```js
const [state, setState] = useState(default);
```
### `useEffect`
Hook used to trigger an action on each render of the component or when one of the watched items changes.
```js
useEffect(() => {
// "side effects" operations
return () => {/* clean up side effect */} // optional
}, [/* list of watched items, empty triggers once */]);
```
### Custom Hooks
```js
// hook definitions
const useCustomHook = () => {
// eventual state definitions
// eventual function definitions
// ...
return { obj1, obj2, ... };
}
const Component(){
// retrieve elements from the hook
const {
obj1,
obj2,
...
} = useCustomHook();
}
```

View file

@ -0,0 +1,156 @@
# Redux Testing
## Tests for Connected Components
Connected components are wrapped in a call to `connect`. Way of solving the problem:
- Wrap component with `<Provider>`. Added benefit: new store dedicated to tests.
- Add named export for unconnected component.
In `Component.js`:
```js
export function Component(props) { /* ... */ } // export unconnected component
export default connect(mapStateToProps, mapDispatchToProps)(Component) // default export of connected component
```
In `Component.test.js`:
```js
import React from "react";
// import enzyme or react testing library
// import mock data
import { Component } from "path/to/Component"; // import unconnected component
// factory to setup test easily
function testHelper(args) {
const defaultProps = {
/* default value for props in each test and required props */,
history = {} // normally injected by react-router, could also import the router
};
const props = { ...defaultProps, ...args };
return mount(<Component {...props} />); // or render if using react testing library
}
it("test description", () => {
const dom = testHelper();
// simulate page iteration
dom.find("selector").simulate("<event>");
// find changed component
// test expected behaviour of component
});
```
## Tests for Action Creators
```js
import * as actions from "path/to/actionCreators";
// import eventual action types constants
// import mock data
it("test description", () => {
const data = /* mock data */
const expectedAction = { type: TYPE, /* ... */ };
const actualAction = actions.actionCreator(data);
expect(actualAction).toEqual(expectedAction);
});
```
## Tests for Reducers
```js
import reducer from "path/to/reducer";
import * as actions from "path/to/actionCreators";
it("test description", () => {
const initialState = /* state before the action */;
const finalState = /* expected state after the action */
const data = /* data passed to the action creator */;
const action = actions.actionCreator(data);
const newState = reducer(initialState, action);
expect(newState).toEqual(finalState);
});
```
## Tests for the Store
```js
import { createStore } from "redux";
import rootReducer from "path/to/rootReducer";
import initialState from "path/to/initialState";
import * as actions from "path/to/actionCreators";
it("test description", () => {
const store = createStore(storeReducer, initialState);
const expectedState = /* state after the update */
const data = /* action creator input */;
const action = actions.actionCreator(data);
store.dispatch(action);
const state = store.getState();
expect(state).toEqual(expectedState);
});
```
## Tests for Thunks
Thunk testing requires the mocking of:
- store (using `redux-mock-store`)
- HTTP calls (using `fetch-mock`)
```js
import thunk from "redux-thunk";
import fetchMock from "fetch-mock";
import configureMockStore from "redux-mock-store";
// needed for testing async thunks
const middleware = [thunk]; // mock middlewares
const mockStore = configureMockStore(middleware); // mock the store
import * as actions from "path/to/actionCreators";
// import eventual action types constants
// import mock data
describe("Async Actions", () => {
afterEach(() => {
fetchMock.restore(); // init fetch mock for each test
});
it("test description", () => {
// mimic API call
fetchMock.mock(
"*", // capture any fetch call
{
body: /* body contents */,
headers: { "content-type": "application/json" }
}
);
// expected action fired from the thunk
const expectedActions = [
{ type: TYPE, /* ... */ },
{ type: TYPE, /* ... */ }
];
const store = mockStore({ data: value, ... }); // init mock store
return store.dispatch(actions.actionCreator()) // act
.then(() => {
expect(store.getActions()).toEqual(expectedActions); // assert
});
});
});
```

View file

@ -0,0 +1,465 @@
# [Redux](https://redux.js.org/)
Redux is a pattern and library for managing and updating application state, using events called *actions*. It serves as a centralized store for state that needs to be used across the entire application, with rules ensuring that the state can only be updated in a predictable fashion.
## Actions, Store, Immutability & Reducers
### Actions & Action Creators
An **Action** is a plain JavaScript object that has a `type` field. An action object can have other fields with additional information about what happened.
By convention, that information is stored in a field called `payload`.
**Action Creators** are functions that create and return action objects.
```js
function actionCreator(data)
{
return { type: ACTION_TYPE, payload: data }; // action obj
}
```
### Store
The current Redux application state lives in an object called the **store**.
The store is created by passing in a reducer, and has a method called `getState` that returns the current state value.
The Redux store has a method called `dispatch`. The only way to update the state is to call `store.dispatch()` and pass in an action object.
The store will run its reducer function and save the new state value inside.
**Selectors** are functions that know how to extract specific pieces of information from a store state value.
In `initialState.js`;
```js
export default {
// initial state here
}
```
In `configStore.js`:
```js
// configStore.js
import { createStore, applyMiddleware, compose } from "redux";
export function configStore(initialState) {
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // support for redux devtools
return createStore(
rootReducer,
initialState,
composeEnhancers(applyMiddleware(middleware, ...))
);
}
// available functions & methods
replaceReducer(newReducer); // replace an existing reducer, useful for Hot Reload
store.dispatch(action); // trigger a state change based on an action
store.subscribe(listener);
store.getState(); // retrieve current state
```
### Reducers
**Reducers** are functions that receives the current state and an action, decide how to update the state if necessary, and return the new state.
Reducers must **always** follow some specific rules:
- They should only calculate the new state value based on the `state` and `action` arguments
- They are not allowed to modify the existing `state`.
Instead, they must make *immutable updates*, by copying the existing `state` and making changes to the copied values.
- They must not do any asynchronous logic, calculate random values, or cause other "side effects"
```js
import initialState from "path/to/initialState";
function reducer(state = initialState, action) {
switch(action.type){
case "ACTION_TYPE":
return { ...state, prop: value }; // return modified copy of state (using spread operator)
break;
default:
return state; // return unchanged state (NEEDED)
}
}
// combining reducers
import { combineReducers } from "redux";
const rootReducer = combineReducers({
entity: entityReducer.
...
});
```
> **Note**: multiple reducers can be triggered by the same action since each one operates on a different portion of the state.
## [React-Redux](https://react-redux.js.org/)
### Container vs Presentational Components
Container Components:
- Focus on how thing work
- Aware of Redux
- Subscribe to Redux State
- Dispatch Redux actions
Presentational Components:
- Focus on how things look
- Unaware of Redux
- Read data from props
- Invoke callbacks on props
### Provider Component & Connect
Used at the root component and wraps all the application.
```js
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { configStore } from 'path/to/configStore';
import initialState from "path/to/initialState";
import App from './App';
const store = configStore(initialState);
const rootElement = document.getElementById('root');
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
rootElement
);
```
```js
// Component.js
import { connect } from 'react-redux';
import { increment, decrement, reset } from './actionCreators';
// const Component = ...
// specifies which state is passed to the component (called on state change)
const mapStateToProps = (state, ownProps /* optional */) => {
// structure of the props passed to the component
return { propName: state.property };
};
// specifies the action passed to a component (the key is the name that the prop will have )
const mapDispatchToProps = { actionCreator: actionCreator };
// or
function mapDispatchToProps(dispatch) {
return {
// wrap action creators
actionCreator: (args) => dispatch(actionCreator(args))
};
}
// or
function mapDispatchToProps(dispatch) {
return {
actionCreator: bindActionCreators(actionCreator, dispatch),
actions: bindActionCreators(allActionCreators, dispatch)
};
}
// both args are optional
// if mapDispatch is missing the dispatch function is added to the props
export default connect(mapStateToProps, mapDispatchToProps)(Component);
```
## Async Operations with [Redux-Thunk](https://github.com/reduxjs/redux-thunk)
**Note**: Redux middleware runs *after* and action and *before* it's reducer.
Redux-Thunk allows to return functions instead of objects from action creators.
A "thunk" is a function that wraps an expression to delay it's evaluation.
In `configStore.js`:
```js
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
function configStore(initialState) {
const composeEnhancers =
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; // support for redux devtools
return createStore(
rootReducer,
initialState,
composeEnhancers(applyMiddleware(thunk, ...)) // add thunks middleware
);
}
```
```js
// usually action on async func success
function actionCreator(arg) {
return { type: TYPE, data: arg };
}
export function thunk() {
return function (dispatch) { // redux-thunk injects dispatch as arg
return asyncFunction().then((data) => { // async function returns a promise
dispatch(actionCreator(data));
})
.catch((error) => {
throw error;
});
};
}
// or using async/await
export async function thunk() {
return function (dispatch) { // redux-thunk injects dispatch as arg
try {
let data = await asyncFunction();
return dispatch(actionCreator(data));
} catch(error) {
throw error;
}
}
}
```
## [Redux-Toolkit](https://redux-toolkit.js.org/)
The Redux Toolkit package is intended to be the standard way to write Redux logic. It was originally created to help address three common concerns about Redux.
Redux Toolkit also includes a powerful data fetching and caching capability dubbed "RTK Query". It's included in the package as a separate set of entry points. It's optional, but can eliminate the need to hand-write data fetching logic yourself.
These tools should be beneficial to all Redux users. Whether you're a brand new Redux user setting up your first project, or an experienced user who wants to simplify an existing application, Redux Toolkit can help you make your Redux code better.
Installation
Using Create React App
The recommended way to start new apps with React and Redux is by using the official Redux+JS template or Redux+TS template for Create React App, which takes advantage of Redux Toolkit and React Redux's integration with React components.
```sh
# Redux + Plain JS template
npx create-react-app my-app --template redux
# Redux + TypeScript template
npx create-react-app my-app --template redux-typescript
```
Redux Toolkit includes these APIs:
- [`configureStore()`][cfg_store]: wraps `createStore` to provide simplified configuration options and good defaults.
It can automatically combines slice reducers, adds whatever Redux middleware supplied, includes redux-thunk by default, and enables use of the Redux DevTools Extension.
- [`createReducer()`][new_reducer]: that lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements.
In addition, it automatically uses the `immer` library to let you write simpler immutable updates with normal mutative code, like `state.todos[3].completed = true`.
- [`createAction()`][new_action]: generates an action creator function for the given action type string.
The function itself has `toString()` defined, so that it can be used in place of the type constant.
- [`createSlice()`][new_slice]: accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.
- [`createAsyncThunk`][new_async_thunk]: accepts an action type string and a function that returns a promise, and generates a thunk that dispatches pending/fulfilled/rejected action types based on that promise
- [`createEntityAdapter`][entity_adapt]: generates a set of reusable reducers and selectors to manage normalized data in the store
- The `createSelector` utility from the Reselect library, re-exported for ease of use.
[cfg_store]: https://redux-toolkit.js.org/api/configureStore
[new_reducer]: https://redux-toolkit.js.org/api/createReducer
[new_action]: https://redux-toolkit.js.org/api/createAction
[new_slice]: https://redux-toolkit.js.org/api/createSlice
[new_async_thunk]: https://redux-toolkit.js.org/api/createAsyncThunk
[entity_adapt]: https://redux-toolkit.js.org/api/createEntityAdapter
### [`configureStore`](https://redux-toolkit.js.org/api/configureStore)
Included Default Middleware:
- Immutability check middleware: deeply compares state values for mutations. It can detect mutations in reducers during a dispatch, and also mutations that occur between dispatches.
When a mutation is detected, it will throw an error and indicate the key path for where the mutated value was detected in the state tree. (Forked from `redux-immutable-state-invariant`.)
- Serializability check middleware: a custom middleware created specifically for use in Redux Toolkit
Similar in concept to `immutable-state-invariant`, but deeply checks the state tree and the actions for non-serializable values such as functions, Promises, Symbols, and other non-plain-JS-data values
When a non-serializable value is detected, a console error will be printed with the key path for where the non-serializable value was detected.
- In addition to these development tool middleware, it also adds `redux-thunk` by default, since thunks are the basic recommended side effects middleware for Redux.
Currently, the return value of `getDefaultMiddleware()` is:
```js
// development
const middleware = [thunk, immutableStateInvariant, serializableStateInvariant]
// production
const middleware = [thunk]
```
```js
import { combineReducers } from 'redux'
import { configureStore } from '@reduxjs/toolkit'
import monitorReducersEnhancer from './enhancers/monitorReducers'
import loggerMiddleware from './middleware/logger'
import usersReducer from './usersReducer'
import postsReducer from './postsReducer'
const rootReducer = combineReducers({
users: usersReducer,
posts: postsReducer,
})
const store = configureStore({
// reducers combined automatically
reducer: rootReducer,
middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(loggerMiddleware),
enhancers: [monitorReducersEnhancer]
})
export default store
```
### [`createAction`](https://redux-toolkit.js.org/api/createAction)
```js
import { createAction } from '@reduxjs/toolkit';
const increment = createAction<number | undefined>('counter/increment');
const action = increment(); // { type: 'counter/increment' }
const action = increment(3); // { type: 'counter/increment', payload: 3 }
increment.toString(); // 'counter/increment'
```
### [`createReducer`](https://redux-toolkit.js.org/api/createReducer)
```js
import { createAction, createReducer } from '@reduxjs/toolkit'
interface CounterState {
value: number
}
const increment = createAction('counter/increment')
const decrement = createAction('counter/decrement')
const incrementByAmount = createAction<number>('counter/incrementByAmount')
const initialState = { value: 0 } as CounterState
const counterReducer = createReducer(initialState, (builder) => {
builder
.addCase(increment, (state, action) => {
state.value++
})
.addCase(decrement, (state, action) => {
state.value--
})
.addCase(incrementByAmount, (state, action) => {
state.value += action.payload
})
})
```
### [`createSlice`](https://redux-toolkit.js.org/api/createSlice)
A function that accepts an initial state, an object of reducer functions, and a "slice name", and automatically generates action creators and action types that correspond to the reducers and state.
Internally, it uses `createAction` and `createReducer`, so it's possible to use Immer to write "mutating" immutable updates.
**Note**: action types will have the `<slice-name>/<reducer-name>` shape.
```js
import { createSlice, PayloadAction } from '@reduxjs/toolkit'
interface CounterState {
value: number
}
const initialState = { value: 0 } as CounterState
const counterSlice = createSlice({
name: 'counter',
initialState,
reducers: {
increment(state) {
state.value++
},
decrement(state) {
state.value--
},
incrementByAmount(state, action: PayloadAction<number>) {
state.value += action.payload
},
},
})
export const { increment, decrement, incrementByAmount } = counterSlice.actions
export default counterSlice.reducer
```
### [`createAsyncThunk`](https://redux-toolkit.js.org/api/createAsyncThunk)
The function `createAsyncThunk` returns a standard Redux thunk action creator.
The thunk action creator function will have plain action creators for the pending, fulfilled, and rejected cases attached as nested fields.
The `payloadCreator` function will be called with two arguments:
- `arg`: a single value, containing the first parameter that was passed to the thunk action creator when it was dispatched.
- `thunkAPI`: an object containing all of the parameters that are normally passed to a Redux thunk function, as well as additional options:
- `dispatch`: the Redux store dispatch method
- `getState`: the Redux store getState method
- `extra`: the "extra argument" given to the thunk middleware on setup, if available
- `requestId`: a unique string ID value that was automatically generated to identify this request sequence
- `signal`: an `AbortController.signal` object that may be used to see if another part of the app logic has marked this request as needing cancellation.
- [...]
The logic in the `payloadCreator` function may use any of these values as needed to calculate the result.
```js
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
const payloadCreator = async (arg, ThunkAPI): Promise<T> => { /* ... */ };
const thunk = createAsyncThunk("<action-type>", payloadCreator);
thunk.pending; // action creator that dispatches an '<action-type>/pending'
thunk.fulfilled; // action creator that dispatches an '<action-type>/fulfilled'
thunk.rejected; // action creator that dispatches an '<action-type>/rejected'
const slice = createSlice({
name: '<action-name>',
initialState,
reducers: { /* standard reducer logic, with auto-generated action types per reducer */ },
extraReducers: (builder) => {
// Add reducers for additional action types here, and handle loading state as needed
builder.addCase(thunk.fulfilled, (state, action) => { /* body of the reducer */ })
},
})
```
## RTK Query
RTK Query is provided as an optional addon within the `@reduxjs/toolkit` package.
It is purpose-built to solve the use case of data fetching and caching, supplying a compact, but powerful toolset to define an API interface layer got the app.
It is intended to simplify common cases for loading data in a web application, eliminating the need to hand-write data fetching & caching logic yourself.
RTK Query is included within the installation of the core Redux Toolkit package. It is available via either of the two entry points below:
```cs
import { createApi } from '@reduxjs/toolkit/query'
/* React-specific entry point that automatically generates hooks corresponding to the defined endpoints */
import { createApi } from '@reduxjs/toolkit/query/react'
```
RTK Query includes these APIs:
- [`createApi()`][new_api]: The core of RTK Query's functionality. It allows to define a set of endpoints describe how to retrieve data from a series of endpoints,
including configuration of how to fetch and transform that data.
- [`fetchBaseQuery()`][fetch_query]: A small wrapper around fetch that aims to simplify requests. Intended as the recommended baseQuery to be used in createApi for the majority of users.
- [`<ApiProvider />`][api_provider]: Can be used as a Provider if you do not already have a Redux store.
- [`setupListeners()`][setup_listener]: A utility used to enable refetchOnMount and refetchOnReconnect behaviors.
[new_api]: https://redux-toolkit.js.org/rtk-query/api/createApi
[fetch_query]: https://redux-toolkit.js.org/rtk-query/api/fetchBaseQuery
[api_provider]: https://redux-toolkit.js.org/rtk-query/api/ApiProvider
[setup_listener]: https://redux-toolkit.js.org/rtk-query/api/setupListeners

View file

@ -0,0 +1,207 @@
# [Svelte](https://svelte.dev/docs)
```sh
npx degit sveltejs/template <project name>
# set project to use typescript
node scripts/setupTypeScript.js
# or using vite
npm init vite@latest
```
## App Entry-point
```js
import App from "./App.svelte"; // import the component
const app = new App({
target: document.body,
props: {
// props passed to the App component
},
});
export default app;
```
## Components (`.svelte`)
### Basic Structure
```html
<!-- code for the component -->
<script lang="ts">
import { Component } from "Component.svelte";
export let prop; // make a variable a prop
</script>
<!-- CSS for the component -->
<style>
/* CSS rules */
/* target elements outside of the current component */
:global(selector) {
}
</style>
<!-- html of the component -->
<!-- dynamic expressions -->
<div>{variable}</div>
<!-- nested components -->
<Component prop="{value}" />
```
### If-Else
```js
{#if <condition>}
// markup here
{:else if <condition>}
// markup here
{:else}
// markup here
{/if}
```
### Loops
```js
{#each array as item, index} // index is optional
// markup here
{/each}
{#each array as item (key)} // use key to determine changes
// markup here
{/each}
```
### Await Blocks
```js
{#await promise}
<p>...waiting</p>
{:then number}
<p>The number is {number}</p>
{:catch error}
<p style="color: red">{error.message}</p>
{/await}
```
### Event Handling
The full list of modifiers:
- `preventDefault` — calls `event.preventDefault()` before running the handler. Useful for client-side form handling, for example.
- `stopPropagation` — calls `event.stopPropagation()`, preventing the event reaching the next element
- `passive` — improves scrolling performance on touch/wheel events (Svelte will add it automatically where it's safe to do so)
- `nonpassive` — explicitly set `passive: false`
- `capture` — fires the handler during the capture phase instead of the bubbling phase
- `once` — remove the handler after the first time it runs
- `self` — only trigger handler if `event.target` is the element itself
```js
<script>
const eventHandler = () => {};
</script>
<button on:event={eventHandler}>
// or
<button on:event={() => eventHandler(args)}>
<button on:event|modifier={eventHandler}>
```
> **Note**: It's possible to chain modifiers together, e.g. `on:click|once|capture={...}`.
## Binding
```html
<script>
let name = "Foo";
</script>
<!-- modify value in real time -->
<input bind:value="{stringValue}" />
<input type="checkbox" bind:checked={boolean}/ >
<!-- ... -->
```
### Reactive declarations & Reactive Statements
Svelte automatically updates the DOM when the component's state changes.
Often, some parts of a component's state need to be computed from other parts and recomputed whenever they change.
For these, Svelte has reactive declarations. They look like this:
```js
let count = 0;
$: double = count * 2; // recalculated when count changes
// or
$: { }
$: <expression>
```
## Routing
[Svelte Routing](https://github.com/EmilTholin/svelte-routing)
```js
<!-- App.svelte -->
<script>
import { Router, Link, Route } from "svelte-routing";
import Home from "./routes/Home.svelte";
import About from "./routes/About.svelte";
import Blog from "./routes/Blog.svelte";
export let url = "";
</script>
<Router url="{url}">
<nav>
<Link to="/">Home</Link>
<Link to="about">About</Link>
<Link to="blog">Blog</Link>
</nav>
<div>
<Route path="blog/:id" component="{BlogPost}" />
<Route path="blog" component="{Blog}" />
<Route path="about" component="{About}" />
<Route path="/"><Home /></Route>
</div>
</Router>
```
## Data Stores
```js
// stores.js
import { writable } from "svelte/store";
export const count = writable(0);
```
```html
<script>
import { onDestroy } from "svelte";
import { count } from ".path/to/stores.js";
const unsubscriber = count.subscribe((value) => {
// do stuff on load or value change
});
count.update((n) => n + 1);
count.set(1);
// or
$count = 1;
onDestroy(unsubscriber);
</script>
<!-- use $ to reference a store value -->
<p>{$count}</p>
```