---
title: 'usthing web tutorial'
disqus: hackmd
---
# USTHING WEB Tutorial
#### Refresh your memory here
===
[TOC]
## Syllabus
### 0.Env Setup
### 1.Basic Typescript
###### -- Combine Json and Typescript
### 2.Basic React
###### -- Combine React and Typescript
#### 3.Basic Html / Css
#### 4.Basic Javascript
#### 5.Basic Next.js
#### 6.Api Calling
#### 7.Practises
#### 8.Basic Bootstrap (optional frontend lib)
## Env Setup
Whenever you using a new system/setup(ios/windows,linux),you need to generate ssh key-pair on that machine and put the public key on github in order to clone or do whatever manipulation to repos on github
### ssh-key
#### this is for when you are using the default key path and name
### steps:
#### 1. ssh-keygen
#### 2. eval $(ssh-agent)
#### 3. ssh-add ~/.ssh/id_rsa
#### 4. cat ~/.ssh/id_rsa.pub or pbcopy < ~/.ssh/id_rsa.pub
#### 5. add the public key on your github settings -> ssh and gpg keys
> Read more about env and ssh key setup here: https://support.atlassian.com/bitbucket-cloud/docs/set-up-an-ssh-key/
### Vscode Extensions (suggest)



### Package Manager
dont mix up your package managers in one repo , or you will see yarn.lock or package.lock file
##### install yarn (suggest)
npm install --global yarn
##### install package with yarn
yarn add <package_name>
##### remove package with yarn
yarn remove <package_name>
> Read more about yarn commands here: https://classic.yarnpkg.com/lang/en/docs/cli/remove/
or
> Read more about npm commands here:
https://docs.npmjs.com/cli/v7/commands/npm
## Basic Typescript (JavaScript With Syntax For Type.)
tsx files for both js/ts(typescript) and html/css
ts files for js/ts only
### Basic Typescript Skills
```typescript
// Primitive Types
string
number
boolean
enum
Symbol
// array of strings / numbers ..
string[] / number[] ...
// union => type string or number
string | number ..
//string "one" or "two" is accepted
"one" | "two"
// readonly -> cannot change
type TustStudent = {
readonly name:string
age:number;
courses:string[];
single:boolean;
}
// declare Interface
// I for Interface (convention)
interface IustStudentInfo {
name:string;
age:number;
}
// extend interface
interface IustStudent extends IustStudentInfo{
// name:string => inherited
// age:number
courses:string[];
single:boolean;
}
```
### Typescript with Json
```typescript=
const student:TustStudent ={
name:'John Doe',
age:22,
courses:['elec 2100','comp2011'],
single:true
}
const students: IustStudent[] = [
student,
{
name: "john",
age: 10,
courses: [],
single: false,
},
];
// inline
const prof : {name:string , age:number} ={
name:"Prof Yip" , age:56
}
```
### Utility Types
```typescript
async function test () :Promise<string>{
return "nice"
}
const awaitedFn :Awaited<Promise<string>>= await test()
type Ttest ={
time:string
value:number
dates:string[]
}
type Tevents = "open" | "close"
//set all fields to optional
type TpartialTest = Partial<Ttest>
//pick fields from types
type TtimeOnly = Pick<Ttest, "time">
//omit fields
type TnameValue =Omit<Ttest ,"dates">
//type mappings
const events:Record<Tevents ,Ttest> ={
open:{
time :"10:00",
value:5,
dates:["2022-12-11"]
},
close:{
time:"12:00",
value:10,
dates:["2012-12-12"]
}
}
type Topen = Exclude<Tevents, "close">
type Topen2 = Extract<Tevents ,"open">
type TtestReturn = ReturnType<typeof test>
type TEvents = Capitalize<Tevents>
// "Open" | "Close"
//explore more by yourself....
```
### Generics
```typescript=
//generic Fn
function firstElement<Type>(arr: Type[]): Type | undefined {
return arr[0];
}
// s is of type 'string'
const s = firstElement(["a", "b", "c"]);
// n is of type 'number'
const n = firstElement([1, 2, 3]);
// u is of type undefined
const u = firstElement([]);
//generic Types
type Tperson<T> ={
name :string
sex:T
}
const Bob :Tperson<'male'> = props?.person
```
### Conditional Types
```typescript=
type ExtractFunctionReturn<T> = T extends (...args: any[]) => infer R ? R : never;
function stringReturner() {
return "A String";
}
type FunctionReturnType = ExtractFunctionReturn<typeof stringReturner>;
```
### Indexed Access Types / Template Literal Types / Mapped Types
```typescript=
//Indexed Access Types
type Person = { age: number; name: string; alive: boolean };
type I2 = Person[keyof Person];
const MyArray = [
{ name: "Alice", age: 15 },
{ name: "Bob", age: 23 },
{ name: "Eve", age: 38 },
];
type Age = typeof MyArray[number]["age"]; // typeof MyArray["age"]
//Mapped Types
type OptionsFlags<Type> = {
[Property in keyof Type]: boolean;
};
type FeatureFlags = {
darkMode: () => void;
newUserProfile: () => void;
};
type FeatureOptions = OptionsFlags<FeatureFlags>;
// type FeatureOptions = {
// darkMode: boolean;
// newUserProfile: boolean;
// }
//Template Literal Types
type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
// type AllLocaleIDs = "welcome_email_id" | "email_heading_id" | "footer_title_id" | "footer_sendoff_id"
```
### Advanced Mapped Types
creating new object types based on existing ones but with modified property names.(using the as clause)
```typescript=
type MappedTypeWithAs<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};
interface Person {
name: string;
age: number;
location: string;
}
type LazyPerson = MappedTypeWithAs<Person>;
// Type is:
// {
// getName: () => string;
// getAge: () => number;
// getLocation: () => string;
// }
```
### Variadic Tuple Types
forwarding parameters and manipulating arrays in a type-safe manner.
```typescript=
type StringNumberBooleans = [string, number, ...boolean[]];
const example: StringNumberBooleans = ["hello", 42, true, false, true];
```
### Labeled Tuple Elements
provide labels to elements in tuple types.
```typescript=
type Address = [street: string, city: string, state: string, postalCode: number];
function printAddress(...address: Address) {
console.log(`Street: ${address[0]}, City: ${address[1]}, State: ${address[2]}, Postal Code: ${address[3]}`);
}
```
### Type Guards
narrow types based on conditions.
```typescript=
function isString(test: any): test is string {
return typeof test === "string";
}
function example(foo: any) {
if (isString(foo)) {
console.log(foo.toUpperCase()); // foo is narrowed to string
}
}
```
### Assertion Functions
function that perform runtime checks and throw an error if a condition is not me
```typescript=
function assertIsNumber(val: any): asserts val is number {
if (typeof val !== "number") {
throw new AssertionError("Not a number!");
}
}
function multiply(x: any, y: any) {
assertIsNumber(x);
assertIsNumber(y);
return x * y; // x and y are narrowed to numbers
}
```
### Recursive Type Aliases
types that refer to themselves in a recursive manner. This is particularly useful for modeling data with a hierarchical or recursive structure, such as trees or linked lists.
```typescript=
type JsonValue = string | number | boolean | null | JsonArray | JsonObject;
interface JsonArray extends Array<JsonValue> {}
interface JsonObject { [key: string]: JsonValue; }
```
### Self Challenge
Q1: how does type AdvancedConfig look like? (Generics and Conditional Types)
```typescript=
type EventConfig<Events extends { kind: string, payload?: any }> = {
[E in Events as `${E["kind"]}Handler`]: E['payload'] extends undefined
? (event: E) => void
: (event: E & { timestamp: Date }) => void;
}
type SquareEvent = { kind: "square", x: number, y: number };
type CircleEvent = { kind: "circle", radius: number, payload: { area: number } };
type AdvancedConfig = EventConfig<SquareEvent | CircleEvent>;
// Usage would look like:
const config: AdvancedConfig = {
squareHandler: (event) => console.log(event.x),
circleHandler: (event) => console.log(event.payload.area, event.timestamp) // Note additional timestamp property
};
```
Q2: how does type GDPRCompliantFields look like? (Enhanced PII Data Extraction with Meta Programming)
```typescript=
type EnhancedExtractPII<Type> = {
[Property in keyof Type]: Type[Property] extends { pii: true }
? { encrypted: boolean, value: string } // Transform the type
: Type[Property];
};
type DBFields = {
id: { format: "incrementing" };
name: { type: string; pii: true };
age: number;
};
type GDPRCompliantFields = EnhancedExtractPII<DBFields>;
// The type GDPRCompliantFields will have the name transformed to include encryption info,
// while other properties remain unchanged.
```
Q3: Create a type that maps HTTP methods to TypeScript types representing the payload structure required for requests and responses.
```typescript=
type HttpMethods = "GET" | "POST" | "PUT" | "DELETE";
type RequestPayloads = {
GET: never; // GET does not have a payload
POST: { data: any };
PUT: { id: number; changes: any };
DELETE: { id: number };
};
type ResponseTypes = {
GET: any[];
POST: { success: boolean; id: number };
PUT: { updated: boolean };
DELETE: { deleted: boolean };
};
type ApiRouteConfig<Method extends HttpMethods> = {
method: Method;
handleRequest: (payload: RequestPayloads[Method]) => ResponseTypes[Method];
};
// Usage would look like:
const postRoute: ApiRouteConfig<"POST"> = {
method: "POST",
handleRequest: (payload) => ({
success: true,
id: 123
})
};
```
Q4: Develop a system where you create type-safe component props definitions using a mapping from prop names to types, which automatically generates optional and required versions of props based on an array of required field names.
```typescript=
type ComponentProps<T, RequiredKeys extends keyof T = never> = {
[P in keyof T as P extends RequiredKeys ? P : never]-?: T[P];
} & {
[P in keyof T as P extends RequiredKeys ? never : P]+?: T[P];
}
type ButtonProps = {
onClick: () => void;
label: string;
size?: 'small' | 'medium' | 'large';
}
type SafeButtonProps = ComponentProps<ButtonProps, 'onClick' | 'label'>;
// A button instance would need to have onClick and label, but size is optional.
const buttonProps: SafeButtonProps = {
onClick: () => console.log("Clicked!"),
label: "Submit",
size: "large" // This is optional
};
```
>check https://www.typescriptlang.org/docs/handbook/2/narrowing.html#using-type-predicates and https://www.typescriptlang.org/docs/handbook/2/classes.html as well
### Summary
#### IustStudent similar to TustSutdent
Difference between Type and Interface:
https://blog.logrocket.com/types-vs-interfaces-in-typescript/#:~:text=Interfaces%20are%20basically%20a%20way%20to%20describe%20data,union%2C%20primitive%2C%20intersection%2C%20tuple%2C%20or%20any%20other%20type.
#### Why use typescript
It implements type system for javascript and detect type errors at dev time
70 - 80 % of run time errors come from type errors
https://stackoverflow.com/questions/12694530/what-is-typescript-and-why-would-i-use-it-in-place-of-javascript
#### Add export in front to use in any file
```typescript
export type Demo ={
name:string
}
```
> Read more about Typescript here: https://www.typescriptlang.org/docs/handbook/2/basic-types.html
## Basic React Hooks(v18.3.1)
### useState
state : a variable in React | setState : setter function to inform react that u want to change the variable
```typescript
const [state,setState] = useState<number | string[] | boolean| IustStudent>()
```
### useEffect
where you run your functions when something changed
##### [] for running only once on first render
```typescript
useEffect(() => {
// execute your function or even write your function here
return () => {
// clean up your useEffect hook here
}
}, [dependencies])
```
#### Example
```typescript
const [userName,setUserName] = useState<string>('')
const [loggedIn,setLoggedIn] = useState<boolean>(false)
useEffect(() => {
let mount = true
const logMeIn = () => {
setUserName(user?.name)
setLoggedIn(true)
}
if(mount && user)logMeIn()
return () => {
mount = false
}
}, [user])
```
#### Example Explanation
Assume user is an object returned by firebase library,
>When user changed from null to something,
we need to update our loggedIn state and userName
so this react hook will be monitoring the user object and declare logMeIn and run it when user object change
#### Advanced concept
Why you need to clean up?
>when you switch to another page ,your function in useEffect might still be running
so we change mount = false when we switch to another page ,
and use mount as the condition to run the function
this prevents memory leak (slow performance)
Memory Leak Details
https://auth0.com/blog/four-types-of-leaks-in-your-javascript-code-and-how-to-get-rid-of-them/
### useCallback
returns a memoized version of the callback that only changes if one of the dependencies has changed. Useful when passing callbacks to optimized child components.
#### Example
```typescript
import { useCallback, useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = useCallback(() => {
setCount(c => c + 1);
}, []); // Dependencies list
return <button onClick={increment}>Count: {count}</button>;
}
```
### useMemo
is used to memoize expensive calculations. If the dependencies haven't changed since the last render, React reuses the memoized value instead of recalculating it.
#### Example
```typescript
import { useMemo } from 'react';
function ExpensiveComponent({ items }) {
const sortedItems = useMemo(() => {
return items.sort((a, b) => a.value - b.value);
}, [items]); // Dependency array
return <div>{sortedItems.map(item => <div key={item.id}>{item.value}</div>)}</div>;
}
```
### useReducer
is an alternative to useState, ideal for managing more complex state logic in components.
#### Example
```typescript
import { useReducer } from 'react';
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'increment'})}>+</button>
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
</>
);
}
```
### useContext
lets you subscribe to React context without introducing nesting.
#### Example
```typescript
import React, { useContext, createContext } from 'react';
const ThemeContext = createContext('light');
function ThemedButton() {
const theme = useContext(ThemeContext);
return <button style={{ background: theme === 'dark' ? 'black' : 'white' }}>Click me</button>;
}
```
### useRef
returns a mutable ref object whose .current property is initialized with the passed argument. The returned object will persist for the full lifetime of the component.
#### Example
```typescript
import { useRef } from 'react';
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
```
### useTransition
helps keep your app responsive during state updates that might cause heavy re-renders.
#### Example
```typescript
import { useTransition, useState } from 'react';
function FilterComponent({ items }) {
const [input, setInput] = useState('');
const [isPending, startTransition] = useTransition();
const handleChange = (e) => {
setInput(e.target.value);
startTransition(() => {
// Perform a heavy filtering operation
});
};
return (
<div>
<input type="text" value={input} onChange={handleChange} />
{isPending ? 'Updating...' : items.map(item => <div key={item.id}>{item.name}</div>)}
</div>
);
}
```
### useDeferredValue
This hook is used to defer the value used for an expensive render to allow the UI to remain responsive.
#### Example
```typescript
import { useDeferredValue, useState } from 'react';
function SearchResults({ searchTerm }) {
const deferredSearchTerm = useDeferredValue(searchTerm);
const results = performSearch(deferredSearchTerm); // Some search function
return (
<ul>
{results.map(result => (
<li key={result.id}>{result.title}</li>
))}
</ul>
);
}
```
### useActionState
Call useActionState at the top level of your component to access the return value of an action from the last time a form was submitted.
#### Example
```typescript
import { useActionState } from "react";
async function increment(previousState, formData) {
return previousState + 1;
}
function StatefulForm({}) {
const [state, formAction] = useActionState(increment, 0);
return (
<form>
{state}
<button formAction={formAction}>Increment</button>
</form>
)
}
```
The form state is the value returned by the action when the form was last submitted. If the form has not yet been submitted, it is the initial state that you pass.
If used with a Server Action, useActionState allows the server’s response from submitting the form to be shown even before hydration has completed.
### useFormStatus
is a Hook that gives you status information of the last form submission.
#### Example
```typescript
import { useFormStatus } from "react-dom";
import action from './actions';
function Submit() {
const status = useFormStatus();
return <button disabled={status.pending}>Submit</button>
}
export default function App() {
return (
<form action={action}>
<Submit />
</form>
);
}
```
#### pitfall:
useFormStatus will not return status information for a <form> rendered in the same component.
The useFormStatus Hook only returns status information for a parent <form> and not for any <form> rendered in the same component calling the Hook, or child components.
```typescript
function Form() {
// 🚩 `pending` will never be true
// useFormStatus does not track the form rendered in this component
const { pending } = useFormStatus();
return <form action={submit}></form>;
}
```
Instead call useFormStatus from inside a component that is located inside <form>.
```typescript
function Submit() {
// ✅ `pending` will be derived from the form that wraps the Submit component
const { pending } = useFormStatus();
return <button disabled={pending}>...</button>;
}
function Form() {
// This is the <form> `useFormStatus` tracks
return (
<form action={submit}>
<Submit />
</form>
);
}
```
## React API(v18.3.1)
### memo
memo is a higher order component for memoizing a component.
```typescript
import React, { memo } from 'react';
const MyComponent = memo(function MyComponent(props) {
/* render using props */
});
```
### createContext
This API creates a Context object. When React renders a component that subscribes to this Context object, it will read the current context value from the closest matching Provider above it in the tree.
```typescript
import { createContext } from 'react';
const MyContext = createContext(defaultValue);
```
### forwardRef
is used to pass refs down to child components.
```typescript
import React, { forwardRef } from 'react';
const FancyButton = forwardRef((props, ref) => (
<button ref={ref} className="FancyButton">
{props.children}
</button>
));
// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;
```
### act
is a utility from the React Testing Library that ensures updates related to state changes, subscriptions, and effects are applied before assertions are made in tests. This utility wraps the code that updates state and asserts the results in a way that reflects what happens in a browser more closely.
```typescript
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { act } from 'react-dom/test-utils';
import Counter from './Counter'; // Assume Counter is a component that increments a count state
test('increments counter', () => {
render(<Counter />);
const button = screen.getByRole('button', { name: /increment/i });
act(() => {
userEvent.click(button);
});
expect(screen.getByText(/count: 1/i)).toBeInTheDocument();
});
```
### lazy
is a function that allows you to render a dynamic import as a regular component. It is used to dynamically load components only when they are needed, which helps to split the code at a more granular level and reduce the size of the initial payload.
```typescript
import React, { Suspense } from 'react';
const LazyComponent = React.lazy(() => import('./LazyComponent'));
function App() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
</div>
);
}
```
### cache (sever components only)
Call cache outside of any components to create a version of the function with caching.
```typescript
import {cache} from 'react';
import calculateMetrics from 'lib/metrics';
const getMetrics = cache(calculateMetrics);
function Chart({data}) {
const report = getMetrics(data);
// ...
}
```
When getMetrics is first called with data, getMetrics will call calculateMetrics(data) and store the result in cache. If getMetrics is called again with the same data, it will return the cached result instead of calling calculateMetrics(data) again.
### use
Call use in your component to read the value of a resource like a Promise or context.
```typescript
import { fetchMessage } from './lib.js';
import { Message } from './message.js';
export default function App() {
const messagePromise = fetchMessage();
return (
<Suspense fallback={<p>waiting for message...</p>}>
<Message messagePromise={messagePromise} />
</Suspense>
);
}
// message.js
'use client';
import { use } from 'react';
export function Message({ messagePromise }) {
const messageContent = use(messagePromise);
return <p>Here is the message: {messageContent}</p>;
}
```
Because Message is wrapped in Suspense, the fallback will be displayed until the Promise is resolved. When the Promise is resolved, the value will be read by the use API and the Message component will replace the Suspense fallback.
#### Pitfall:
use cannot be called in a try-catch block. Instead of a try-catch block wrap your component in an Error Boundary, or provide an alternative value to use with the Promise’s .catch method.
### React with Typescript
```typescript
// declare state with string
const [name ,setName] = useState<string>('')
// declare state with array of string
const [arr ,setArr] = useState<string[]>([])
// declare state with object type ustStudent
const [student,setStudent] =useState<TustStudent | null>(null)
// declare state with array of ustStudents
const [courseStudents,setCourseStudents] =useState<TustStudent[]| null>(null)
// setState type
setName:(value:string) => void
or
setName:(value:typeof name) => void
// type with function params
// void mean function return void
const logStudentInfo = (name:string,age:number):void =>{
console.log('student name',name)
}
```
### React Components and Props
```typescript=
function Welcome(props) {
return <h1>Hello, {props?.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
```
### Conditional Rendering
```typescript=
const [show,setShow] = useState(false)
export const Demo =() =>{
return(
<>
{show && <p>show is true</p>}
{show ? <p>show is true</p> : <p>show is false</p>}
</>
)
}
```
### List and Keys
###### Keys help React identify which items have changed, are added, or are removed. Keys should be given to the elements inside the array to give the elements a stable identity:
```typescript=
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li key={number.toString()}>
{number}
</li>
);
```
### Dont ' s
Infinte Loops
```typescript=
const [state,setState] = useState('')
useEffect(() => {
setState('one')
}, [state])
```
Map without Keys
```typescript=
sth.map(d => (
<div></div>
))
```
#### explanation
This useEffect hook will create an infinite loop. Because the hook is monitoring state , but you are changing the state inside the hook , so this action will keep looping
## Basic Html/Css
##### Center a div
```css=
display:flex;
justify-content:center;
align-self:center;
```
##### Align HTML elements horizontally in a div
```css=
display:flex;
flex-direction:row;
column-gap: 50px;
```
##### Text and Font related css
``` css=
font-size: 5em;
text-align: center;
font-family: "poppins"; // import from google fonts
font-size: 35px;
font-weight: bold;
color: #3145f5;
```
##### div structure
``` css=
height:50;
width:100;
border-radius:25px;
box-sizing: border-box;
```
##### Padding and Margin
```css=
margin: 10rem; //space outside div
padding: 10rem; //space inside div
```
##### useful properties
```css=
display:inline;
opacity:0.5;
z-index:1;
font-size:12px;
background-color:white;
font-weight:200
```
> Read more about HTML and CSS here:
> https://www.w3schools.com/css/css_rwd_intro.asp
>
## Basic Javascript
javascript methods is actually faster than any third party function libs(e.g lodash )
##### Data Structures
```typescript=
//Map
const map = new Map<string , number>([["apples", 500],
["bananas", 300]);
map.set('one' ,1); //inferred type => numbers
const num = map.get('one'); //1
const check:boolean = map.has('two'); // false
const size= map.size //3
//Set
const set:Set<number> = new Set([2,3]);
set.add(1)
set.has(4) // false
...
```
##### Array Methods
```typescript=
//map
const users:{firstName:string , lastName:string}[] = [
{firstName : "Susan", lastName: "Steward"},
{firstName : "Daniel", lastName: "Longbottom"},
{firstName : "Jacob", lastName: "Black"}
];
const userFullnames = users.map(function(element){
return `${element.firstName} ${element.lastName}`;
})
//flat
const arr1 = [0, 1, 2, [3, 4]];
console.log(arr1.flat());
// expected output: [0, 1, 2, 3, 4]
//filter
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]
//concat
const array1 = ['a', 'b', 'c'];
const array2:string[] = ['d', 'e', 'f'];
const array3 = array1.concat(array2);
console.log(array3);
// expected output: Array ["a", "b", "c", "d", "e", "f"]
//includes
const pets = ['cat', 'dog', 'bat'];
console.log(pets.includes('cat')); // expected output: true
console.log(pets.includes('at')); // expected output: false
```
> Read more about Javascript Methods here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes
#### Advanced skills
```typescript=
const num1 =10;
const num2 = 20;
//ternary form
num1 === num2 ? console.log("yes") : console.log('No')
//shorthand
const nums:{num1:number,num2:number} ={
//instead of num1:num1 ....
num1,num2
}
//instead of <Component num1={num1} />
<Component {...{num1}}/>
// destructuring
const {num1} = nums
//note : make sure num1 exist in nums in order to use destructuring
//if not , use below technique to prevent runtime error
const num = nums?.num1
```
## Basic Next.js
#### Link Component Navigation
```typescript=
import Link from 'next/link';
<h1 className="title">
Dont Click Me <Link href="/foo/bar">Click Me</Link>
</h1>
```
In Nextjs, you can use Link component instead of `<a href></a>`.
### Server side rendering
####
getStaticProps
```typescript=
export async function getStaticProps(context) {
//You can do whatever function you want, such as calling API.
return {
props: {}, // will be passed to the page component as props
}
}
```
Nextjs will pre-render this page **ONLY at build time** with using the props returned by getStaticProps.
#### getServerSideProps
```typescript=
export async function getServerSideProps(context) {
//You can do whatever function you want, such as calling API.
return {
props: {}, //data will be passed to the page component as props
}
}
```
Next.js will pre-render the page on **each request** using the data returned by getServerSideProps.
### Routes
Next.js has a file-system based router built on the concept of pages.
When a file is added to the **/pages** directory, it's automatically available as a route.
The dynamic input from user will be treated as **"param"** (useful for Server side rendering)
#### Index Routes
```
pages/index.js → /
pages/blog/index.js → /blog
```
file name called "index" will automatically routed as root.
#### Nested routes
```
pages/foo/bar.js → /foo/bar
pages/foo/bar/foobar.js → /foo/bar/foobar
```
#### Dynamic route
```
pages/blog/[foo].js → /blog/:foo (/blog/hello-world)
```
file name with [] will be treated as dynamic routing page. By default, users are expected to enter anything and redirected to this component.
```
pages/post/[...bar].js → /post/* (/post/foo/bar/foobar/i_can_keep_going)
```
Similar with JavaScript/TypeScript, by adding [...], it will catch all the routes afterward.
#### getStaticPaths
If a page has Dynamic Routes and uses "getStaticProps", it needs to define a list of paths to be statically generated.
```typescript=
export async function getStaticPaths() {
return {
//set the expected params for user
paths: [{ params: { id: '1' } }, { params: { id: '2' } }],
fallback: false, // can also be true or 'blocking'
}
}
```
Note:
>getStaticPaths must be used with getStaticProps
You cannot use getStaticPaths with getServerSideProps
## Api Calling (Axios)
```typescript=
//basic get request
export const getUser = async (signal:AbortSignal) => {
try {
const response = await axios.get('/user?ID=12345' , signal);
if(response)return response?.data
} catch (error) {
console.error(error);
}
}
//with useEffect
const [user ,setUser] = useState()
useEffect(() => {
let mount = true
const controller = new AbortController();
const fetchUser =async (signal:AbortSignal) =>{
const data = await getUser(signal);
if(data)setUser(data)
}
if(mount)fetchUser(controller.signal)
return () => {
mount = false
controller.abort();
};
}, []);
```
#### Explanation
pass in controller.signal to axios has similar effect as clean up effect in useffect hook.When user switch to other pages , we abort the controller and cancel the api request
## React Query
```typescript=
import { QueryClient, QueryClientProvider, useQuery } from 'react-query'
const queryClient = new QueryClient()
export default function App() {
return (
<QueryClientProvider client={queryClient}>
<Example />
</QueryClientProvider>
)
}
function Example() {
const { isLoading, error, data } = useQuery('repoData', () =>
fetch('https://api.github.com/repos/tannerlinsley/react-query').then(res =>
res.json()
)
)
if (isLoading) return 'Loading...'
if (error) return 'An error has occurred: ' + error.message
return (
<div>
<h1>{data.name}</h1>
<p>{data.description}</p>
<strong>👀 {data.subscribers_count}</strong>{' '}
<strong>✨ {data.stargazers_count}</strong>{' '}
<strong>🍴 {data.forks_count}</strong>
</div>
)
}
```
## React Hook Form
```typescript=
import { useForm, SubmitHandler } from "react-hook-form";
type Inputs = {
example: string,
exampleRequired: string,
};
export default function App() {
const { register, handleSubmit, watch, formState: { errors } } = useForm<Inputs>();
const onSubmit: SubmitHandler<Inputs> = data => console.log(data);
console.log(watch("example")) // watch input value by passing the name of it
return (
/* "handleSubmit" will validate your inputs before invoking "onSubmit" */
<form onSubmit={handleSubmit(onSubmit)}>
{/* register your input into the hook by invoking the "register" function */}
<input defaultValue="test" {...register("example")} />
{/* include validation with required or other standard HTML validation rules */}
<input {...register("exampleRequired", { required: true })} />
{/* errors will return when field validation fails */}
{errors.exampleRequired && <span>This field is required</span>}
<input type="submit" />
</form>
);
}
```
## Best Practices and Refs
>Team Guidelines
1. fork the repo
2. create a new branch for each task
3. commit frequently by following conventional commits
4. create pull request on github after finishing the task
5. make sure unnecessary changes to other files is removed , you should see your pull request mostly involve additions
#### Conventional Commits
https://www.conventionalcommits.org/en/v1.0.0-beta.2/
#### React Best Practises
https://github.com/mithi/react-philosophies
#### Typescript Best Practises
https://itnext.io/mastering-typescript-21-best-practices-for-improved-code-quality-2f7615e1fdc3
#### Typescript Design Goals
https://github.com/microsoft/TypeScript/wiki/TypeScript-Design-Goals/53ffa9b1802cd8e18dfe4b2cd4e9ef5d4182df10
#### Basic Design Pattern With Web (MVC)
https://developer.mozilla.org/en-US/docs/Glossary/MVC
#### Design Patterns
https://refactoring.guru/design-patterns/factory-method