# React Notes
###### tags: `React` `JavaScript` `GUI` `App` `Web Technology`

Learn React as a beginner with JavaScript development experience.
ref:
- [從 JavaScript 到 React - Next.js](https://hackmd.io/@shibarashinu/HyLUtS173)
- [Learn React - React.dev](https://react.dev/learn/describing-the-ui)
- [React Hooks - w3schools](https://www.w3schools.com/react/react_hooks.asp)
- [30 Days Of React - github](https://github.com/Asabeneh/30-Days-Of-React)
impl tutorial:
- [Build and Deploy an Amazing 3D Web Developer Portfolio in React JS | Beginner Three.js Tutorial - JavaScript Mastery](https://www.youtube.com/watch?v=0fYi8SGA20k)
- [Build and Deploy a React Native App | 2023 React Native Course Tutorial for Beginners - JavaScript Mastery](https://www.youtube.com/watch?v=mJ3bGvy0WAY)
- [Build and Deploy a React Admin Dashboard App - JavaScript Mastery](https://www.youtube.com/watch?v=jx5hdo50a2M)
### Using React Scenario
The React framework is a library that manipulates UI components, creating a logical, MVC encapsulation module. And it also take advantage of optimizing the DOM tree lifetime updates and the rendering processes.
### Basic usage
1. use React library & JSX compiler (Babel)
```jsx=
// React library
<script src="/js/react-core.js"></script>
<script src="/js/react-dom.js"></script>
// Babel (for compiling following JSX)
<script src="/js/babel.js"></script>
<script type="text/jsx">
const app = document.getElementById("app");
ReactDOM.render(<h1>Hello</h1>, app);
</script>
```
2. JSX syntax
```jsx=
<script type="text/jsx">
function MyComponent() {
return (
<div class="component">
<MyContainer objItem="i" objItem2="i2" />
<MyContainer objItem="ii" arr={ [ "li0", "li1" ] } />
</div>
);
}
function MyContainer({ objItem, objItem2, arr }) {
return (
<div class={ `${objItem}-my-container` }> // class="i-my-container"
{ objItem2 || "default" } // "i2": { ... } JSX syntax escape characters to javascript
</div>
<div>
{arr.map((item) => (
<li key={item.id}>{ item }</li> // key: React "id" to identify different components
))}
</div>
);
}
const app = document.getElementById("app");
ReactDOM.render(<div><MyComponent /></div>, app);
</script>
```
3. DOM event listener
```jsx=
function Banner() {
function homeClick() {
window.location = "/";
}
return (
<div>
<a onClick={homeClick}>Home</a>
</div>
);
}
```
4. useState (for every Component)
```jsx=
import { useState } from 'react';
function HomePage() {
const [ storeValue, setValue ] = React.useState("init value");
const [ value2, setValue2 ] = React.useState("init value2");
return (
<a onClick={ ()=>setValue("clicked") }>{ storeValue }</a>
);
}
```
5. useRef (1. no new rendering process triggered compared to useState / 2. ref hook to get dom element)
```jsx=
import { useRef } from 'react';
function SendButton() {
const ref = useRef("init");
return (
<button onClick={
()=>{
ref.current = ref.current && "send";
} }
/>
);
}
```
```jsx=
import { useRef } from 'react';
function App() {
const componentRef = useRef("init");
useEffect(()=> {
if(!!componentRef.currect)
console.log(componentRef);
})
return (
<Component ref={componentRef} />
);
}
```
6. useReducer (states transition: initial => case dispatch => new state)
[A cure for React useState hell - Steve (Builder.io)](https://www.youtube.com/watch?v=sGdW4Amolq4&ab_channel=Steve%28Builder.io%29)
```jsx=
const dispatcher = {
add: (state) => { count: state.count + 1 }, // return blend new obj as new state instead of modified state
sub: (state) => { count: state.count - 1 }
}
function reducer(state, action) {
const dispatchFunc = dispatcher[action.type];
return dispatchFunc ? dispatchFunc(state) : state;
}
const Buttons = () => {
const [state, dispatch] = useReducer(reducer, { count: 0 });
const addClick = () => { dispatch({ type: "add" }) };
const subClick = () => { dispatch({ type: "sub" }) };
return (
<div>
<button onClick={ addClick } />
<button onClick={ subClick } />
</div>);
};
```
7. useContext (for interior-cross var get / set within Component block)
```jsx=
// Context-definition-lib.js
import { createContext } from 'react';
export const MyLayerContext = createContext({
level: 0,
name: "root",
state, setState
});
```
```jsx=
// Component.js
import { useState, useContext } from 'react'
import { MyLayerContext } from './Context-definition-lib.js'
export default function Section({ children }) {
const [state, setState] = useState("initial");
const parentLayerContext = useContext(MyLayerContext);
return (
<section>
<div>{ name + '-' + layer }</div>
<MyLayerContext.Provider
value={{
layer: parentLayerContext.layer + 1,
name: "section",
state, setState // so children can get / set parent provider's state
}}
>
{ children }
</MyLayerContext.Provider>
</section>
);
}
```
8. useEffect (== Component drawcall)
:::warning
**Virtual DOM Management**
If a virtual DOM's element is unmounted, React bottom-up cleans up the corresponding subtree, that is:
1. remove the element from the actual DOM tree.
2. remove internal references, corresponding resources & invoke their cleanup callbacks, so to prevent memory leaks.
:::
```jsx=
import { useState, useEffect } from 'react'
function Timer() {
const [state, setState] = useState(0);
useEffect(() => {
setTimeout(() => {
setState((origin) => origin + 1);
}, 1000);
const cleanupFunc = () => { db.disconnect(); };
return cleanupFunc;
}, [state, state2]); // <- render if any dependency value changes
return <div>state: {state}</div>;
}
```
(8-2. useLayoutEffect (sync drawcall))
9. useCallback (call this Component to render if the observed variables have changed)
```jsx=
const Arr = ({ arr, insert }) => {
return (
<>
<h2>My Array</h2>
{ arr.map((item, ind) => (<p key={index}>{todo}</p>)) }
<button onClick={ insert }>Add Item</button>
</>
);
};
const App = () => {
const [arr, setArr] = useState([]);
const insert = useCallback(() => {
setArr((arr) => [...arr, "new item"]);
}, [arr]);
return <Arr arr={arr} insert={insert} />;
};
```
10. useMemo (same as useCallback but use it as a React component)
> [useMemo vs. useEffect + useState - StackOverflow](https://stackoverflow.com/questions/56028913/usememo-vs-useeffect-usestate)
> The `useEffect` and `setState` will cause extra renders on every change: the first render will "lag behind" with stale data and then it'll immediately queue up an additional render with the new data.
> ```jsx=
> function expensiveCalculation(x) { return x + 1; };
> ```
> Lets suppose x is initially 0:
> - The `useMemo` version immediately renders 1.
> - The `useEffect` version renders null, then after the component renders the effect runs, changes the state, and queues up a new render with 1.
>
> Then if we change x to 2:
> - The `useMemo` runs and 3 is rendered.
> - The `useEffect` version runs, and renders 1 again, then the effect triggers and the component reruns with the correct value of 3.
```jsx=
const App = () => {
const [count, setCount] = useState(0);
const result = useMemo(() => expensiveCalculation(count), [count]);
const increment = () => {
setCount((count) => count + 1);
};
return (
<div>
Count: {count}
<button onClick={increment}>+</button>
<h2>Expensive Calculation</h2>
{result}
</div>
);
};
const expensiveCalculation = (num) => {
for (let i = 0; i < 1000000000; i++) {
num++;
}
return num;
};
```
11. useQuery (auto fetch when var changed)
```jsx=
const result = useQuery("/api/books", { var });
```
100. my custom use hook
```jsx=
const myUseFetch = (url) => {
const [data, setData] = useState(null); // ! concatenate the React useState hook
useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => setData(data));
}, [url]);
return [data];
};
export default myUseFetch;
```