# React

## Life Cycle

<figure><img src="https://1374779285-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MFW3x2aqEO8GF2kr3VU%2Fuploads%2FXWlc9pF4ZZOIqA2liBcu%2Fimage.png?alt=media&#x26;token=2f834309-6190-46d3-becf-973f2304d1b2" alt=""><figcaption></figcaption></figure>

## Re-render

<figure><img src="https://1374779285-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MFW3x2aqEO8GF2kr3VU%2Fuploads%2FlyAFK2wHSkXnePnfhh1K%2Fimage.png?alt=media&#x26;token=f1f11b9a-8b06-4fdb-a380-ae75f3a726fb" alt=""><figcaption></figcaption></figure>

* There is element in the index.html which id is root and render the react dom element
* The react dom object itself is a virtual dom which is lightweight, which looks like:

```tsx
import React from 'react'
import { createRoot } from 'react-dom/client'

const spanElement = React.createElement('span', {
  children: '123'
});
console.log(spanElementElement);
console.log(<span>123</span>);
/* 
{
  "type":"span",
  "key":null,
  "ref":null,
  "props":{"children":"123"},
  "_owner":null,
  "_store":{}
} 
*/
createRoot(document.getElementById('root')!).render(
  spanElement
)
```

* For every state change, the page will be re-rendered again, the state , variable , function, useEffect in the render scope will be independent to previous one
* For each rendering, the functional component will be returned and then triggered useEffect
* The virtual dom will be saved in memory and will be compared with the previous virtual dom with its internal differing algorithm, and just update the changed part on the real dom which is into dom which id is root so as to increase the efficiency

![The real dom](https://1374779285-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MFW3x2aqEO8GF2kr3VU%2F-MOCmMm3F7PBl3nz1QBB%2F-MOCt7hXtYZBg-jZa7SI%2F%E8%9E%A2%E5%B9%95%E6%88%AA%E5%9C%96%202020-12-11%20%E4%B8%8A%E5%8D%882.22.57.png?alt=media\&token=d4ea08ea-fa18-4536-b910-c1f96fe14d2d)

{% embed url="https://dev.to/karthikraja34/what-is-virtual-dom-and-why-is-it-faster-14p9" %}

{% embed url="https://zh-hant.reactjs.org/docs/reconciliation.html" %}

## Hook

### useState

* When you call `setState`, React schedules the state update and marks the component for a re-render. This scheduling is asynchronous
* React batched state updates in event handlers to reduce the number of re-rendering

```javascript
// number is a state, setNumber is a setter method
const [number, setNumber] = useState(1);

// put the value into setter to set the value directly
setNumber(2);
// put the update function into setter 
// to set the value which is based on previous value
setNumber(prevNum => prev + 1);
// Not recommended
setNumber(number + 1);
```

```javascript
function A () {
    const [count, setCount] = useState(4);
    setCount(count + 1);
    setCount(count + 1);
    console.log('A: ', count) // ?
}
function B () {
    const [count, setCount] = useState(4);
    setCount(prev => prev + 1);
    setCount(prev => prev + 1);
    console.log('B: ', count) // ?
}
// Answer
// A: 5
// B 6
```

```javascript
function init () {
    console.log('run function');
    return 4;
}
// Run Everytime when changing the state
const [count, setCount] = useState(4);
const [count, setCount] = useState(init());
// Run only the very first time when your component render
const [count, setCount] = useState(() => init());
```

### useEffect

* It is used to listen the dependencies change, e.g: state, and execute the side effect, which is equal to lifecycle event of class component
* When the component is mounted, the side effect will be triggered once first.&#x20;
* When component is unmounted, the return function will be triggered and based on the previous useEffect. After the new user interface finish re-rendering, , and finally trigger the new useEffect function&#x20;

```tsx
"use client"

import { Button,} from "@mui/material";
import { useEffect,useState } from "react";
export default function Home() {
  const [num, setNum] = useState<number>(0);
  useEffect(()=>{
    console.log("update" , num);
    return ()=> {
      console.log("return function", num);
    }
  },[num])

  // update 0
  // return function 0
  // update 1
  return (
    <div>
       <Button variant="contained" onClick={()=>{
        setNum((prev)=>prev+1)
       }} >Hello world</Button>
    </div>
  );
}
```

* The function of useEffect will always be triggered in every re-rendering as there is no dependency array

```javascript
useEffect(async () => {
    const { data } = await axios.get(
      "https://sampleapis.com/futurama/api/info",
      {}
    );
    console.log("data", data);
  });
```

* The function of useEffect will only be triggered once as the dependency array is empty, there will not have any dependency change to trigger useEffect

```javascript
useEffect(async () => {
    const { data } = await axios.get(
      "https://sampleapis.com/futurama/api/info",
      {}
    );
    console.log("data", data);
  },[]);
```

* The function of useEffect will be triggered due to the change of the state&#x20;

```javascript
 useEffect(async () => {
    const { data } = await axios.get(
      "https://sampleapis.com/futurama/api/info",
      {}
    );
    console.log("data", data);
  }, [state]);
```

#### Case Study 1

* As the state and variable in render scope is put in the useEffect,  it is not recommended to put an empty array as it may cause potential bug

```jsx
const App = () =>{
    const [count , setCount] = useState(0);
    const test = 2; 
    // Wrong
    useEffect(()=>{
        setCount(count+1);
        test = 3;
    },[])
    // Correct
    useEffect(()=>{
        setCount(count+1);
    }, [count, test])
}
```

#### Case Study 2

* As the function in render scope is put in useEffect, it is recommended to put the function in the dependency array
* As we do not want the useEffect always be triggered as the function is always be changed in every re-rendering, so we use useCallback to save the function except the dependency is changed

```jsx
const App = () =>{
    const [count , setCount] = useState(0);
    
    // Wrong
    useEffect(()=>{
        addCount();
    }, [])
    
    const addCount = () => {
        setCount(count+1);
    }
    
    // Correct
    useEffect(() => {
        addCount();
    }, [addCount])
    
    const addCount = useCallback(() => {
        setCount(count+1);
    }, [count])
}
```

#### Case Study 3

* As async function have the delay, we cannot make sure of order of the setState. In order to prevent from set the wrong data which is based on the the value or state in previous rendering, it is recommended to make return function to stop setting wrong value after the state is updated

```jsx
function Article({ id }) {
  const [article, setArticle] = useState(null);

  useEffect(() => {
    let didCancel = false;

    async function fetchData() {
      const article = await API.fetchArticle(id);
      if (!didCancel) {
        setArticle(article);
      }
    }

    fetchData();

    return () => {
      didCancel = true;
    };
  }, [id]);

  // ...
}
```

### UseContext

* Share all the data from component with upper layer to components with lower layer without passing props

```typescript
// Mother.js
import React, { createContext } from "react";
import Son from "./Son";
type ParentContext = {
  data:string
  setData: (data:string) => void
}
export const ParentContext = createContext<ParentContext>({data: ""});
const Mother = () => {
  const [data, setData] = useState("Mother");
  return (
    <ParentContext.Provider value={{data,setData}}>
      <Son />
    </ParentContext.Provider>
  );
};

export default Mother;
```

```javascript
// Son.js
import React, { useContext } from "react";
import { ParentContext } from "./context";
const Son = () => {
  const {data,setData} = useContext(ParentContext);
  return <span>{data}</span>;
};
export default Son;
```

### useReducer

* It is an advanced version of useState, since the setting function of the useState is only allow one situation and one return value. But useReducer can return different base on the the type, it is more suitable to handle more complicated logic

```javascript
// 一個 Reducer 用來描述根據指令執行對應的動作，會回傳一個新的 state 物件，是個純函式
const todoReducer = (state, action) => {
    // 判斷指令
    switch (action.type) {
        case 'ADD_TODO':
            let newKey = 1
            if (state.list.length !== 0){
                newKey = state.list[state.list.length - 1].listKey + 1
            }
            return {
                ...state,
                list: [...state.list, { listKey: newKey, name: action.payload.name }]
            }
        default:
            return state
    }
}

// 初始資料，為 state 的初始值，通常會在這裡把結構描述完整
const initState = {
    list: [{ listKey: 1, name: 'first' }]
}

const Todo = () => {
    const [listName, setListName] = useState('')
    
    /*
     使用 useReducer 將 Reducer 和 初始 State 個別傳入，
     會回傳一個陣列，在此使用解構賦值將陣列的位置 0 及 1 分別放到 state 和 dispatch 中，
     state 會隨著 Reducer 會傳的 state 做改變，
     dispatch 是用來和 Reducer 溝通的 Function 。
    */
    const [state, dispatch] = useReducer(todoReducer, initState)
    const addTodo = () => {
        //使用 dispatch 呼叫 Reducer 處理 state ，這個參數會被傳進 Reducer 的 action 中
        dispatch({ type: 'ADD_TODO', payload: { name: listName } })
        setListName('')
    }

    return (
        <div>
            <input value={listName}
                onChange={e => setListName(e.target.value)} />
            <input type='button' value='新增' onClick={addTodo} />
            {state.list.map((list) => {
                return (
                    <p key={list.key}>
                        <input type='button' value='移除'
                            onClick={() => { removeTodo(list.listKey) }} />
                        {list.name}
                    </p>
                )
            })}
        </div>
    )
}
```

#### useContext/useReducer vs Redux

* useContext/useReducer : it is easier to setup and  more suitable to put variables with low-frequency update on it , since every time the variable passed by useContext, the area inside the provider will be re-rendered
* Redux: it is more complicated to setup, and middleware is allowed to use to handle async function. each component will subscribe (add listener) to their connected  state. If the correspondent state is changed, the listener will be triggered, so that only that component will be re-rendered but not whole of the area inside the provider

### useCallback

* When the component is re-rendered, the functions will also be re-rendered. The purpose of useCallback is return the memorized callback function until the one of the dependency is changed.&#x20;

```javascript
 const [delta, setDelta] = useState(1);
 const [c, setC] = useState(0);

 // the function will keep the same, which means delta always be 1,
 // and listen to the dependency c , if c is changed , 
 // the function will be re-rendered and updated
 const incrementDeltaWithCallBack = useCallback(() => {
    setDelta(delta + 1);
    console.log("increaseDelta");
  }, [c]);
  
 const incrementWithCallBack = useCallback(() => {
    setC(c + 1);
    console.log("increment");
  }, [delta]);
```

### &#x20;useMemo

* When the component is re - rendered, the variable will also be re-rendered. The purpose of useMemo is return the memorized value until the one of the dependency is changed.&#x20;

```javascript
  const [delta, setDelta] = useState(1);
  
  // even setDelta is triggered, but value of testMemo will 
  // be the same, always be 1, will not be re-rendered
  const testMemo = useMemo(() => delta, []);
  
```

#### useMemo vs useCallback

* The effect of useMemo can equal to useCallback in this case

```javascript
 const incrementDeltaWithCallBack = useCallback(() => {
    setDelta((delta) => delta + 1);
    console.log("increaseDelta");
  }, [delta]);
  
 const incrementDeltaWithMemo = useMemo(() => () => {
    setDelta((delta) => delta + 1);
    console.log("increaseDelta");
  }, [delta]);
```

#### The drawback of abusing useMemo/ useCallback

* The time of the first time re-rendering will be much larger as it memorizes the value/function
* &#x20;The ram consumed in the browser will be much larger

#### The condition of using useMemo/ useCallback

* The variable require long time to be rendered , for example : have a larger loop and return the result
* The function is called in useEffect

### useRef

* The current property will be initialized by passing the argument , and if the current is changed, it will be saved, but the component will not be re-rendered, it can be used to store the value which is not related to the ui&#x20;

```javascript
  const testRef = useRef(0);
  
  const test = () => {
    console.log(testRef.current); // 0
    testRef.current++;
    return (<div>{testRef.current}</div>)
    // next time testRef.current will be 1 ...
    // but the ui still show 0 
  }
```

* The reference object can be acted as the ref of the element, so that the current property will be corresponded to the html element. We can make use good use of the reference to manipulate the element, such as focus&#x20;

```javascript
const App = () => {
    const testRef = useRef();
    const test = () => {
        console.log(testRef.current); // <input..../>
        testRef.current.focus();
     }
    return (
        <div>
            <input ref={testRef} type="text"/>
        </div>
    )
}
```

### useImperativeHandle

* To lets you customize the handle exposed as a ref
* Mainly for exposing the child state, method to the parent or your own method

{% code title="App.js" %}
```javascript
import MyInput from './MyInput.js';

export default function Form() {
  const ref = useRef(null);

  function handleClick() {
    // to apply the method passed by child component
    ref.current.focus();
  }

  return (
    <form>
      <MyInput placeholder="Enter your name" ref={ref} />
      <button type="button" onClick={handleClick}>
        Edit
      </button>
    </form>
  );
}
```
{% endcode %}

{% code title="MyInput.js" %}
```javascript
import { forwardRef, useRef, useImperativeHandle } from 'react';

const MyInput = forwardRef(function MyInput(props, ref) {
  const inputRef = useRef(null);

  useImperativeHandle(ref, () => {
    return {
      focus() {
        inputRef.current.focus();
      },
      scrollIntoView() {
        inputRef.current.scrollIntoView();
      },
    };
  }, []);

  return <input {...props} ref={inputRef} />;
});

export default MyInput;
```
{% endcode %}

### useLayoutEffect

* `useLayoutEffect` is a version of [`useEffect`](https://react.dev/reference/react/useEffect) that fires before the browser repaints the screen, to enhance the user experience and the shift of component

```javascript
function Tooltip() {
  const ref = useRef(null);
  const [tooltipHeight, setTooltipHeight] = useState(0); // You don't know real height yet

  useLayoutEffect(() => {
    const { height } = ref.current.getBoundingClientRect();
    setTooltipHeight(height); // Re-render now that you know the real height
  }, []);

  // The component only render once when using layout effect
  // useLayoutEffect: render with height
  // useEffect: render with 0 -> render with height
}
```

* The code inside `useLayoutEffect` and all state updates scheduled from it **block the browser from repainting the screen.** When used excessively, this makes your app slow. When possible, prefer [`useEffect`.](https://react.dev/reference/react/useEffect)

### useTransition

* The function you pass to `startTransition` must be synchronous. React immediately executes this function, marking all state updates that happen while it executes as Transitions.
* The hook can be used prioritize the state update . A state update marked as a Transition will be interrupted by other state updates and marked as lower priority
* If there are multiple ongoing Transitions, React currently batches them together.
* The state update inside the startTransition will be non-blocking, which means that the state update will not be blocked by heavy computation and be freeze, it will interrupt the slow rendering immediately

```jsx
import { useTransition } from 'react';

 const [isPending, startTransition] = useTransition();

// Urgent: Show what was typed
setInputValue(input);

// Mark any non-urgent state updates inside as transitions
startTransition(() => {
  // Transition: Show the results
  setSearchQuery(input);
});
```



### useDeferredValue

* The deferred value is considered as a low priority, its deferred “background” rendering is interruptible even if the deferred value is updated.
* &#x20;For example, if you type into the input again, React will abandon it and restart with the new value.  Also, network request is pending, the rendering is also be suspended

```jsx
function App() {
  const [text, setText] = useState('');
  const deferredText = useDeferredValue(text);
  return (
    <>
      <input value={text} onChange={e => setText(e.target.value)} />
      <SlowList text={deferredText} />
    </>
  );
}
```

* `useDeferredValue` lets you prioritize updating the input (which must be fast) over updating the result list (which is allowed to be slower)

### useOptimistic (React 19)

* It provides a function that takes the current state and the input to the action, and returns the optimistic state to be used while the action is pending.
* The state is called the “optimistic” state because it is usually used to immediately present the user with the result of performing an action, even though the action actually takes time to complete.

```jsx
import { useOptimistic, useState, useRef } from "react";
import { deliverMessage } from "./actions.js";

function Thread({ messages, sendMessage }) {
  const formRef = useRef();
  async function formAction(formData) {
    addOptimisticMessage(formData.get("message"));
    formRef.current.reset();
    await sendMessage(formData);
  }
  const [optimisticMessages, addOptimisticMessage] = useOptimistic(
    messages,
    (state, newMessage) => [
      ...state,
      {
        text: newMessage,
        sending: true
      }
    ]
  );

  return (
    <>
      {optimisticMessages.map((message, index) => (
        <div key={index}>
          {message.text}
          {!!message.sending && <small> (Sending...)</small>}
        </div>
      ))}
      <form action={formAction} ref={formRef}>
        <input type="text" name="message" placeholder="Hello!" />
        <button type="submit">Send</button>
      </form>
    </>
  );
}

export default function App() {
  const [messages, setMessages] = useState([
    { text: "Hello there!", sending: false, key: 1 }
  ]);
  async function sendMessage(formData) {
    const sentMessage = await deliverMessage(formData.get("message"));
    setMessages((messages) => [...messages, { text: sentMessage }]);
  }
  return <Thread messages={messages} sendMessage={sendMessage} />;
}

```

### useActionState (React 19)

* It pass `useActionState` an existing form action function as well as an initial state, and it returns a new action that you use in your form, along with the latest form state and pending state

```jsx
function ChangeName({ name, setName }) {
  const [error, submitAction, isPending] = useActionState(
    async (previousState, formData) => {
      const error = await updateName(formData.get("name"));
      if (error) {
        return error;
      }
      redirect("/path");
      return null;
    },
    null,
  );

  return (
    <form action={submitAction}>
      <input type="text" name="name" />
      <button type="submit" disabled={isPending}>Update</button>
      {error && <p>{error}</p>}
    </form>
  );
}
```

### Custom Hook

* Can do a custom hook and apply to different component instead of making high     order component

![](https://1374779285-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MFW3x2aqEO8GF2kr3VU%2F-MNMRz-IsbKxnKLYJB57%2F-MNMUgD2QaWEiYEk-EVv%2F%E8%9E%A2%E5%B9%95%E6%88%AA%E5%9C%96%202020-11-30%20%E4%B8%8B%E5%8D%8812.51.05.png?alt=media\&token=a5616d84-aa0a-4256-a68e-482243700a62)
