Category Archives: Uncategorized
Pure Functions
Pure vs Impure (procedures)
Functional programming almost always use pure functions.
Creates and returns value based on input parameters and causes no side effects
1) Changing value globally
2) Changing value of input
3) Throwing exception
4) Logging or printing to screen, writing to file, change to db.
5) Invoking other functions that have side-effects
Ramda
Higher Order Function
Higher Order Function – function that takes function as input parameter or returns a function.
map is higher order because it takes function as input.
other functions that returns functions are higher order.
Reduce (javascript)
1 |
const numbers = [1,2,3]; |
Reduce sums up all the items in the array where the first parameter is the callback and second param is the starting value.
1 2 3 4 |
const result = numbers.reduce( (sum, item) => sum + item, 0 // starting value ); |
1 2 3 4 5 6 |
const grades = [60, 55, 80, 90, 99, 92, 75, 72]; const total = grades.reduce(sum); function sum(total, grade) { return total + grade; } |
Let’s group grades into an object:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
const letterGradeCount = grades.reduce(groupByGrade, {}); function groupByGrade(resObj, grade) { const { a = 0, b = 0, c = 0, d = 0, f = 0 } = resObj; if (grade >= 90) { return {...resObj, a: a + 1} } else if (grade >= 80) { return {...resObj, b: b + 1} } else if (grade >=70) { return {...resObj, c: c + 1} } else if (grade >= 60) { return {...resObj, d: d + 1} } else { return {...resObj, f: f + 1} } } |
When to use useMemo, useEffect, and useCallback
ref – https://www.geeksforgeeks.org/when-to-use-usecallback-usememo-and-useeffect/
useCallback
Let’s see this in the following code, doubleFactory creates and returns a function:
1 2 3 4 5 6 7 8 9 10 11 12 |
function doubleFactory(){ return (a) => 2*a; } const double1 = doubleFactory(); const double2 = doubleFactory(); double1(8); // gives 16 double2(8); // gives 16 double1 === double2; // false double1 === double1; // true |
doube1 and double2 doubles the value passed to them and are created by the same factory function. The two functions even when they share the same code, are not equal, here (double1 === double2) evaluates to false.
When to use useCallback: In React, a component usually has some callback function created within it.
1 2 3 4 5 6 7 8 9 10 |
function MyComponent(){ // HandleChange is created on every render const handleChange = () => {...}; return <> ... </>; } |
handleChange function objects are different on every rendering of MyComponent. And there are several cases when we may want the same function object between multiple renderings.
In our example, we have getItems which is executed whenever we enter some digits.
We pass this inside a child component List to be rendered.
So her’es how it works. Our input is being changed inside input element. Since the state changes, our variables (such as getItems) will also change and get re-calculated.
And since getItems is passed into List component, it will see that if getItems has changed, then it needs to re-render.
App.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
import React, { useState} from "react" import List from "./List" function App(){ const [input, setInput] = useState(1); const [light, setLight] = useState(true); const getItems = () => { return [input + 10, input + 100]; } {/* Style for changing the theme */} const theme = { backgroundColor: light ? "White": "grey", color: light ? "grey" : "white" } return <> <div style={theme}> <input type="number" value={input} onChange={event => setInput(parseInt(event.target.value))} /> <button onClick={() => setLight(prevLight => !prevLight)}> {light ? "dark mode":"light mode"} </button> <List getItems={getItems} /> </div> </>; } export default App; |
In our List, we look at getItems array. If it changes, we update and set our items to this new getItems.
List
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import React, { useEffect, useState } from "react" function List({ getItems }){ /* Initial state of the items */ const [items, setItems] = useState([]); /* This hook sets the value of items if getItems object changes */ useEffect(() => { console.log("Fetching items"); setItems(getItems()); }, [getItems]); /* Maps the items to a list */ return <div> {items.map(item => <div key={item}>{item}</div>)} </div> } export default List; |
So
1) parent input state changes from Input Element
2) state change makes everything re-calculate, including getItems.
3) Since getItems is passed into child component, child sees getItems has changed, and thus, will re-render via useEffect.
The following will be the output when a user enters a number into the input field.
It can be seen from the console log that when the app is rendered for the first time, items are fetched, and “fetching items” are printed. Now if we input some different numbers, we see that items are fetched once again. This is the expected result.
Now the weird thing is,
when we press the button to change the theme,
we see that the getItems is still being called…even when the input field is not modified!
The reason behind this behavior is that when we press the button,
the app component is rerendered
and hence the function getItems() inside App is again created and we know that two objects are referentially different and thus re-rendered.
But why does the the button press trigger the component to re-reproduce getItem() again?
Because useState causes a re-render on the call to the setState method. It does not have any dependencies like useMemo or useEffect. This is why our component re-renders.
This is why getItem get called again even though the input field is not modified.
Thus, useEffect hook calls the setItems and prints “Fetching items” as its dependency has changed.
The solution to the above problem:
Here we can use the useCallback function to memoise the getItems() function depending upon the input number.
1 2 3 |
const getItems = useCallback(() => { return [input + 10, input + 100]; }, [input]); |
We don’t want to recreate the function unless the input changes, and hence, on pressing the button (changing the theme) items will not be fetched.
Now we use the useCallback hook to memoize the getitems function which takes the function and a dependency list. The dependency list in our case includes only the input.
useMemo
There are two cases where using useMemo can be helpful:
Case 1
When a component uses a value computed using a time-consuming function.
1 2 3 4 5 6 7 8 9 10 |
function MyComponent(){ const [data, setData] = useState(0); const number = verySlowFunction(data); return <div>{number}</div>; } function verySlowFunction(input){ ...heavy work done here return value; } |
Here the slow function is called every time MyComponent is rendered, maybe because some stateful variable is changed or some other component caused the rerendering.
Solution: By memoizing the returned value of the slow function using the useMemo hook we can save ourselves from the delay it may cause.
1 2 3 4 5 6 7 8 9 10 11 12 |
function MyComponent(){ const [data, setData] = useState(0); const number = useMemo(() => { return verySlowFunction(data)}, [data]); return <div>{number}</div>; } function verySlowFunction(input){ ...heavy work done here return value; } |
here we use the useMemo hook to cache the returned value and the dependency list contains the data stateful variable. Now every time the component is rendered, if the data variable is not altered, we get the memoized value without calling the CPU intensive function. Hence, it improves the performance.
Case 2
Now consider another scenario when we have a component that does something when some data changes, for example, a let’s take the hook useEffect which logs if some dependency changes.
1 2 3 4 5 6 7 8 9 10 |
function MyComponent() { const [number, setNumber] = useState(0); const data = { key: value }; useEffect(() => { console.log('Hello world'); }, [data]); } |
In the above code, every time the component is rendered, “Hello world” is printed on the console due to the fact that the data object that is stored in the previous render is referentially different in the next render and hence the useEffect hook runs the console.log function. In real-world useEffect can contain some functionality that we don’t want to be repeated if its dependencies do not change.
Solution: We can memoize the data object using the useMemo hook so that rendering of the component won’t create a new data object and hence useEffect will not call its body.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function MyComponent(){ const [number, setNumber] = useState(0); const data = useMemo( () => { return { key: value }}, number); useEffect(() => { console.log('Hello world'); }, [data]); } |
Now when the component renders for the second time and if the number stateful variable is not modified then console.log() is not executed.
useEffect
useEffect: In react, side effects of some state changes are not allowed in functional components. useEffect is always called after the render phase of the component. This is to avoid any side-effects from happening during the render commit phase (as it’d cause the component to become highly inconsistent and keep trying to render itself). This hook takes a function to be executed and a list of dependencies, changing which will cause the execution of the hook’s body.
To understand its proper use. let’s see a simple example:
Example: Consider a scenario where we have to fetch some data from some API once the components are mounted. In the example code, we simulate the server with our data object with values of different colours and fruits. We want to print the list of items depending on the button being pressed. Hence we have two state variables currentChoice and items which are modified by pressing the buttons. When a button is pressed it changes the currentChoice and the body of useEffect is called and current choice’s items are printed using a map. Now if we don’t use useEffect, every time a button is pressed data will be fetched from the server even if the choice does not change. In such a condition this hook helps us to not call the fetching logic unless our choice changes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import React, { useEffect, useState} from "react" function App(){ /* Some data */ const data = { Colors: ["red", "green", "yellow"], Fruits: ["Apple", "mango", "Banana"] } /* Initial states */ const [currentChoice, setCurrentChoice] = useState("Colors"); const [items, setItems] = useState([]); /* Using useEffect to set the data of currentchoice to items and console log the fetching... */ useEffect(() => { setItems(data[currentChoice]); console.log("Data is fetched!"); }, [currentChoice]); return <> <button onClick={() => setCurrentChoice("Colors")}>Colors</button> <button onClick={() => setCurrentChoice("Fruits")}>Fruits</button> {items.map(item => {return <div key={item}>{item}</div>})} </>; } export default App; |
When the application loads for the first time, data is fetched from our fake server. This can be seen in the console in the image below. And when we press the Fruits button, appropriate data is again fetched from the server and we can see that “Data is fetched” is again printed in the console. But if we press the Fruits button again, we don’t have to get the data from the server again as our choice state does not change.
Hence, a useCallback hook should be used when we want to memoize a callback,
and to memoize the result of a function to avoid expensive computation we can use useMemo.
useEffect is used to produce side effects to some state changes.
usMemo vs useCallback
useMemo recalculates a value if the elements in its dependency array change (if there are no dependencies – i.e. the array is empty, it will recalculate only once). If the array is left out, it will recalculate on every render…just like useEffect. The difference herein lies in that it runs during the render of the component and not before.
useEffect is called after each render when a certain state has changed in the dependency array, or is left out altogether. If the array is empty, it will only be run once on the initial mount (and unmount if you return a cleanup function).
Extends (typescript)
Let’s define a base class Person that takes in a parameter name, and assigns it to a protected property.
1 2 3 4 5 6 7 8 9 10 11 |
class Person { constructor(protected name: string) { this.name = name; } display() { console.log(`name is: ${this.name}`); } work() { console.log(`${this.name} is not doing anything`); } } |
We then create Employee that extends from Person. It has a super reference to its parent class Person. Since it extends from Person, it can access property name. In our constructor, we simply take in a name and append a Emp stamp on it. We also override the work function from parent class.
1 2 3 4 5 6 7 8 9 10 11 12 |
class Employee extends Person { constructor(param: string) { super(`${param} [Emp]`); } work() { console.log(`${this.name} is sitting in a Cubicle`); } } function getToWork(person: Person) { person.work(); } |
When we declare functions, we can use the base class as parameters and pass in any kind of children classes. This is called Sharing common behavior
1 2 3 4 |
const a : Person = new Person("ricky"); const b: Employee = new Employee("ricky"); getToWork(a); getToWork(b); |
Abstract classes
Abstract classes requires children classes to implement abstract interface.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
abstract class Person { constructor(protected name: string) { this.name = name; } // No implementations abstract work (): void; abstract display(): void; } class Employee extends Person { constructor(param: string) { super(`${param} [Emp]`); } work() { // implemented abstract method work √ console.log(`${this.name} is sitting in a Cubicle`); } // uh oh, missing display() X } |
If you extend an abstraction and do not implement it, you’ll get compiler errors:
Unlike concrete classes, abstract classes cannot be instantiated.
Hence, in order to use it
1 2 3 4 5 |
function getToWork(person: Person) { person.work(); } const b: Employee = new Employee("ricky"); getToWork(b); |
The thing about extends from either concrete/abstract classes is that it satisfies several SOLID principles:
Liskov Substitution Principle
“Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it.”
Since we define valid subtypes, each implementation should work and be interchangeable as long as it implements the contract. In our case, each implementation (Employee, Manager..etc) should work and be interchangeable with parameter Person because we implement the contract.
As long as our implementation extends from our base class, any pointers or reference to base class can use our derived classes.
1 |
getToWork(extendedFromBase); |
Dependency Inversion Principle (DIP) – Depends upon abstraction, not concretion
instead of doing:
1 2 3 4 5 6 |
const a: Employee = new Employee("Joy"); a.makeCoffee(); const b: Employee = new Employee("Ricky"); b.pushPapers(); const c: Employee = new Employee("David"); c.chatAtWaterCooler(); |
We can make call its abstraction instead:
1 |
employees.forEach(employee => employee.work()); |
- Dependency upon abstraction – Don’t depend on the concrete implementation. Rather, depend on abstraction.
- Liskov Principle – functions with base class reference shall be able to use extended classes
plays into Open Closed Principle.
Let’s say we want to create a function that calculates the area of an array of shapes. With our current design, it might look like that:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function calculateAreasOfMultipleShapes( shapes: Array<Rectangle | Circle> ) { return shapes.reduce( (calculatedArea, shape) => { if (shape instanceof Rectangle) { return calculatedArea + shape.width * shape.height; } if (shape instanceof Circle) { return calculatedArea + shape.radius * Math.PI; } }, 0 ); } |
The issue with the above approach is that when we introduce a new shape, we need to modify our calculateAreasOfMultipleShapes function. This makes it open for modification and breaks the open-closed principle.
1 2 3 |
interface Shape { getArea(): number; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
class Rectangle implements Shape { ... public getArea() { return this.width * this.height; } } class Circle implements Shape { ... public getArea() { return this.radius * Math.PI; } } |
Now that we are sure that all of our shapes have the getArea function, we can use it further.
1 2 3 4 5 6 7 8 9 10 |
function calculateAreasOfMultipleShapes( shapes: Shape[] ) { return shapes.reduce( (calculatedArea, shape) => { return calculatedArea + shape.getArea(); }, 0 ); } |
Now when we introduce a new shape, we don’t need to modify our calculateAreasOfMultipleShapes function. We make it open for extension but closed for modification.
Deep Copying objects using JSON stringify and parse
Serialize and De-serialize
ref – https://dev.to/nas5w/js-fundamentals-object-assignment-vs-primitive-assignment-5h64
One method that can be used to deep copy an object is to serialize and de-serialize the object. One common way to do this is using JSON.stringify and JSON.parse.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
const a = { name: 'Joe', dog: { name: 'Daffodil', }, }; const b = JSON.parse(JSON.stringify(a)); b.name = 'Eva'; b.dog.name = 'Jojo'; console.log(a); // { // name: 'Joe', // dog: { // name: 'Daffodil', // }, // } console.log(b); // { // name: 'Eva', // dog: { // name: 'Jojo', // }, // } |
However, it does not work on function objects:
ref – https://stackoverflow.com/questions/18089033/json-stringify-does-not-process-object-methods
fetching data from remote server
ref – https://javascript.plainenglish.io/from-fetch-api-to-useeffect-and-axios-the-many-ways-of-fetching-api-data-367757ea5ac6
fetch( ) — the Fetch API method
A few months ago, I was primarily fetching data in JavaScript and React using the fetch() API. It’s the easiest, and most readily available way to get data, since it is built into most modern browsers (with exception of Internet Explorer as of me writing this blog).The fetch() API
1 2 3 4 5 6 7 |
fetch('https://api.example.com/items') .then(res => res.json()) .then( // promise (result) => { this.setState({result}); } ) |
It calls the fetch() method, which takes in one argument, the resource. This is the path to the data you want to fetch. This can be your API data such as a link, or a request object. It then returns a promise, which contains a response object. Since the response that we get back is just an HTTP response, we append the json() method to the response, so that we get back the actual JSON formatted data as our response.
On a side note, a major disadvantage of the fetch API is handling errors.
In my example above, I didn’t factor my code to handle errors. And this can be bad, because even if the url sends me an 404 error (meaning page not found), we still send that as a response without breaking our code. I will show you how to handle fetch errors in the next two methods below.
fetch with useEffect
Since hooks are becoming more common in how we use React, the hooks way of fetching data is using the useEffect method. The Effect Hook adds the ability to do the same function as componentDidMount in our first example, or to perform other side effects, but in a function component.
As the example above shows, we used a class component. The useEffect() lets us use componentDidMount, componentDidUpdate, componentDidUnmount that we would in classes, in function components, but it’s all packaged into a single API — useEffect!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
const [race, setState] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { // subscribe code fetch('https://api.example.com/items') .then(res => { // first responder if (res.ok) { return res } else throw res; }) .then(dataArr => { // valid data! setRace(dataArr); }) .catch((err) => { setError(err); // invalid data! }) .finally(() => { // always set loading to false so UI not blocked setLoading(false); }); // return () => {} // unsubscribe code }, []); |
If our response is okay, we go ahead and return that response. However, if our response isn’t okay, say there’s an error in our response, we throw the response as an error, that our .catch callback will handle.
Then in the .finally callback, we use it as a function that will show us our data or an error, should our response be okay or not.
Axios
Axios is an open-source library for making data requests. In order to use axios, you have to first install it as it does not come built in like fetch or useEffect in React. You can install it with package managers like yarn or npm.
Axios supports all modern browsers, even Internet Explorer.
You can also use it in vanilla JavaScript, React, Vue.js, and Angular.
Axios also has better error handling and performs automatic transformations. It lets us cut down a lot of our code!
1 2 3 4 5 6 7 8 9 10 |
axios('....') .then((response) => { // valid data! setData(response.data); }) .catch(error => { // if there is an error, it'll jump here setError(error); }) .finally(() => { // must set loading to false setLoading(false); }); |
We were able to cut down the response because Axios handles the first callback where we check to see if a response is okay and give us an error if it’s not.
Interface vs Type (typescript)
ref – https://pawelgrzybek.com/typescript-interface-vs-type/
Interfaces are restricted to an object type
Interface declarations can exclusively represent the shape of an object-like data structures. Type alias declarations can create a name for all kind of types including primitives (undefined, null, boolean, string and number), union, and intersection types. In a way, this difference makes the type more flexible. In theory every type declaration that you can express with an interface, you can recreate using a type alias. Lets have a look at an example that can be represented using a type alias but is beyond the power of an interface.
1 |
type info = string | { name: string }; |
You can merge interfaces but not types
Multiple declarations with the same name are valid only when used with interface. Doing so doesn’t override previous one but produces a merged result containing members from all declarations.
1 2 3 4 5 6 7 8 9 10 11 12 |
interface DudeInterface { name: string; } interface DudeInterface { age: number; } const pawel: DudeInterface = { name: "Pawel Grzybek", age: 31 }; |
Type aliases can use computed properties
The in keyword can be used to iterate over all of the items in an union of keys. We can use this feature to programmatically generate mapped types. Have a look at this example using type aliases.
1 2 3 4 5 6 7 8 9 10 |
type Keys = "firstname" | "surname" type DudeType = { [key in Keys]: string } const test: DudeType = { firstname: "Pawel", surname: "Grzybek" } |
Unfortunately we cannot take advantage of computed properties in an interface declaration.
resolution of both (types and interfaces) happens in the same phase. No more circular references
1 2 3 4 5 6 7 8 |
type Dude = string | Pals; interface Pals extends Array<Dude> {} const a: Dude = "haha"; console.log(a); // "haha" const b: Pals = [a]; console.log(b); // ["haha"] |
Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
type User = { id: number; email: string; first_name: string; }; type GetUsersResponse = { // type data: User[]; }; function axiosGet () { return { title: "mr", address: "east norwood", } } const response : GetUsersResponse = axiosGet(); |
Solution is we need to make sure axiosGet returns at least a subset of properties that matches type GetUsersResponse.
In our case, it is data: User[]
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function axiosGet () { const userA: User = { id: 5, email: "rtsao@uci.edu", first_name: "ricky" } return { title: "mr", address: "east norwood", data: [userA] } } |