# 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`