# react note
## 關聯筆記
- [mobx](/h43YmMLoTdS6gjiCtvh8iQ)
## create react app
```shell=
# pure app
npx create-react-app my-app
# TypeScript app
npx create-react-app my-app --template typescript
```
<https://create-react-app.dev/docs/getting-started/>
---
## sample
### useMemo
```jsx=
function test({ age }) {
const [name, setName] = useState("");
// bad, will update every rerender
const user = { name, age };
// good
const memoUser = useMemo(() => {
return { name, age };
}, [name, age]);
// watch by useEffect
useEffect(() => {
console.log(user)
}, [user]);
useEffect(() => {
console.log(memoUser);
}, [memoUser]);
}
```
---
## 雜項紀錄
- node attribute 的 class 因為和 js es6 class 關鍵字衝突, 因此改為使用 `className` 替代
- vscode 的 emmet 會在 `.tsx` 內自動轉換
- 另一位是 `for` -> `htmlFor`
- `onClick` with `React.UIEvent`
- 使用 `React.Component<XXX>` 定義 prop 的型別, 這個會影響到祖物件的型別推判.
對應 vue 的 props.
```
No overload matches this call.
Overload 1 of 2, '(props: {} | Readonly<{}>): TextInput', gave the following error.
Type '{ title: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<TextInput> & Readonly<{}> & Readonly<{ children?: ReactNode; }>'.
Property 'title' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<TextInput> & Readonly<{}> & Readonly<{ children?: ReactNode; }>'.
Overload 2 of 2, '(props: {}, context: any): TextInput', gave the following error.
Type '{ title: string; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<TextInput> & Readonly<{}> & Readonly<{ children?: ReactNode; }>'.
Property 'title' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<TextInput> & Readonly<{}> & Readonly<{ children?: ReactNode; }>'.ts(2769)
```
ref: https://fettblog.eu/typescript-react/components/
- `<input>`.`onChange` -> `(e: React.ChangeEvent) => void`
- 使用 [Computed property names](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names) 加上 typescript 會不知道怎樣處理型別推斷
ref: [Computed property key names should not be widened #13948](https://github.com/Microsoft/TypeScript/issues/13948)
先用 `any` 過渡:
```typescript=
let data: any = { [propName]: inputValue };
this.setState(data);
```
- `<datalist>` 內的 `<option>` 用 function 包裝的話直接invoke
```htmlmixed=
<datalist id="the-input">{this.historList()}</datalist>
```
- [react-id-generator](https://www.npmjs.com/package/react-id-generator): 需要動態產生ID避免衝突用.
- [React: creating a href inside `<li>`](https://stackoverflow.com/questions/44990778/react-creating-a-href-inside-li/44990803)
- [React site warning: The href attribute requires a valid address. Provide a valid, navigable address as the href value jsx-a11y/anchor-is-valid](https://stackoverflow.com/questions/52801051/react-site-warning-the-href-attribute-requires-a-valid-address-provide-a-valid)
```
href="/#"
href="javascript:;"
href="javascript:void(0);"
```
取代 `href="#"`
## 疑難雜症
- stop from submit
```typescript=
const onFormSubmit = (e: React.FocusEvent<HTMLFormElement>) => {
e.preventDefault();
};
```
- `Cannot update a component (xxx) while rendering a different component (xxx)`
- Recoil 組件
- ref: <https://github.com/facebookexperimental/Recoil/issues/12>
```typescript=
setUsers(() => {
setCreating(false) // 這行會被標記
setWaitingUser(undefined);
})
```
理由還沒有很清楚, 但改成關注 waiting user 再呼叫 setCreating 便可解除
---
## hooks
### 對照 class component 生命週期
```javascript=
useEffect(() => {
console.log('componentDidMount & componentDidUpdate');
return () => {
console.log('componentDidUpdate & componentWillUnmount')
}
}, [])
```
## useContext
### 為何無法正確傳遞變數?
- 這裡必須使用 Node style 方式呼叫子物件
```typescript=
// X: 這種呼叫方式無法正確傳遞
{Sub()}
// O: 使用 Node style 即可
<Sub />
```
### others
- `Context.Provider` 不可穿插在 `react-bootstrap` 的 `<Tabs>` & `<Tab>` 之間.
### 參考
- [How To useContext With useReducer](https://hswolff.com/blog/how-to-usecontext-with-usereducer/)
- [透過 React CreateContext 搭配 React useContext 與 useReducer 來做 Global State Manager](https://whien.medium.com/%E9%80%8F%E9%81%8E-react-usecontext-%E8%88%87-usereducer-%E4%BE%86%E5%81%9A-global-state-manager-bed30fb1f08b)
---
## useReducer
### 被觸發兩次 dispacther?
- 看起來正確使用的情況下, reducer 不該有 side effect(觸發多次會有不同結果)
### 參考
- [useReducer dispatch calls reduce twice #16295](https://github.com/facebook/react/issues/16295)
- [為什麼我的 useReducer 會被執行兩次?在 React hooks 官方文件沒有清楚告訴你的 useReducer 的 bail out 機制](https://jason-memo.dev/posts/why-useReducer-run-twice-useReducer-bailout-mechanism-that-official-document-dont-tell/)
---
## useRef
### 動態大量參考物件
```typescript=
const iframeDomRef = useRef<Record<string, HTMLIFrameElement | null>>({});
...
return (
<div>
{urlObjList.map((b) => {
return (
<iframe
src={b.url}
key={b.id}
ref={(e) => {
iframeDomRef.current[b.id] = e; // 在這裡儲存 element
}}
/>
);
})}
</div>
);
```
### 參考
- [How can I use multiple refs for an array of elements with hooks?](https://stackoverflow.com/questions/54633690/how-can-i-use-multiple-refs-for-an-array-of-elements-with-hooks)
- [从一个需求出发,聊聊useRef三兄弟](https://juejin.cn/post/6888616874171432973)
---
## 節點事件型別對照
### 如何確認型別?
先從 IDE 追蹤確認該事件欄位的型別, 例如 `onClick`:
```typescript=
onClick?: MouseEventHandler<T>;
```
去除 `Handler` 通常就是對應的型別名稱:
```typescript=
type MouseEventHandler<T = Element> = EventHandler<MouseEvent<T>>;
```
這裡的 `MouseEvent` 就是對應的事件型別.
### 常用範例
```typescript=
// DOMAttributes
// - onClick
React.MouseEvent<HTMLElement>
// Button
// - onClick
React.MouseEvent<HTMLButtonElement>
// Form.Control
// - onChange
React.ChangeEvent<HTMLInputElement>
React.ChangeEvent<HTMLSelectElement>
React.ChangeEvent<HTMLTextAreaElement>
// Element list base on HTMLElement
// HTMLButtonElement
// HTMLDivElement
// HTMLFormElement
// HTMLHtmlElement
// HTMLIFrameElement
// HTMLInputElement
// HTMLLabelElement
// HTMLTableElement
// HTMLTextAreaElement
// HTMLVideoElement
// HTMLWebViewElement
```
---
## [inline css](https://zh-hant.reactjs.org/docs/dom-elements.html#style)
```typescript=
// DONT'T
return <div style="width: 10px">demo</div>
// DO
// 個人推薦 TS 加上 `CSSProperties` 型別, 可以更好讀&使用
const theStyle:CSSProperties = { width: "1.5rem" }
return <div style={theStyle}>demo</div>
```
---
## links
- [各流派 React 状态管理对比和原理实现](https://zhuanlan.zhihu.com/p/394106764)
- [react hooks + mobx usage of summary](https://juejin.cn/post/6921320490409836551)
- mobx 解釋相當直接且帶有應用範例
- [React Hooks 使用误区,驳官方文档](https://juejin.cn/post/7046358484610187277)
###### tags: `note` `react`