--- tags: REACT --- # [筆記] React - vue為雙向綁定資料與畫面,連動 - React單向,改資料更新畫面,更新畫面不會影響到資料 - `useState`, `useEffec` 最重要的兩個東東 ## 參考 - [傳奇人物筆記Dan](https://overreacted.io/) - [必看文章 A Complete Guide to useEffect](https://overreacted.io/a-complete-guide-to-useeffect/) ## JSX - 經babel編譯 ```htmlembedded= <button type="button">Click Here!</button> ``` ```javascript= // function,props,children React.createElement("button", { type: "button", }, "Click Here!"); ``` ```htmlembedded= <div> <button type="button">Click Here!</button> </div> ``` ```javascript= React.createElement("div", null, React.createElement("button", { type: "button" }, "Click Here!")); ``` ## PropTypes `檢查參數型態` ```javascript= import PropTypes from 'prop-types' MyComponent.propTypes = { optionalArray: PropTypes.array, optionalBool: PropTypes.bool.isRequired, optionalFunc: PropTypes.func, // An object taking on a particular shape optionalObjectWithShape: PropTypes.shape({ color: PropTypes.string, fontSize: PropTypes.number }), } ``` # State操作 ## 1. 新增 - 解構 ```javascript= setTodos([ { id, content: inputValue, isDone: false, }, ...todos, ]) ``` ## 2. 刪除 - filter ```javascript= const handleTodoDelete = id => { setTodos( todos.filter((todo) => todo.id !== id ), ) } ``` ## 3. 修改 - map ```javascript= const handleToggleIsDone = id => { setTodos( todos.map((todo) => { if(todo.id === id) todo.isDone = !todo.isDone return todo }), ) } ``` ### a 的 href 防 javascript ``` <!-- 例 --> javascript:alert(2) ``` # Hooks [Hook flow圖](https://raw.githubusercontent.com/donavon/hook-flow/master/hook-flow.png) [useHooks網站](https://usehooks.com/) [從 Hooks 開始,讓你的網頁 React 起來](https://ithelp.ithome.com.tw/articles/10216355) ## 重要觀念 1. 只能在component第一層 2. 不能被function或 if-elase等包起來 ## useEffect - render完要做什麼事?(瀏覽器畫完畫面後想做什麼事) - `array` 作為可選的第二個參數 ```javascript= import { useEffect } from 'react' useEffect(()=>{ console.log('執行完畢') }) // 僅在count更改時才重新執行 effect useEffect(() => { document.title = `You clicked ${count} times`; }, [count]); ``` - 傳空陣列,只有第**一次render會執行** ```javascript= useEffect(() => { fetch('https://jsonplaceholder.typicode.com/todos/1') .then(res=>{ console.log(res) }) }, []); ``` - cleanup effect return 上個state值 ```javascript= useEffect(() => { console.log('current ', value) let i = value if(i <= 10) { i++ setValue(i) console.log('setting ', i) } // cleanup function return () => { // 上一個value值 console.log('cleanup', value) } }, [value]) ``` ```javascript= useEffect(() => { WebSocket.CONNECTING(userID).subscribe(() => { // ... }) // cleanup function return () => { // 清掉上一個userID WebSocket.disconnect(userID) } }, [userID]) ``` ## useLayoutEffect - render完,瀏覽器 `paint` 前執行 # Hook Flow (Life Cycle) [Hook flow圖](https://raw.githubusercontent.com/donavon/hook-flow/master/hook-flow.png) ## Mount ### lazy initialized - 只執行一次 - useState給初始值(這邊只執行一次 ## Update - render - update dom - cleanup LayoutEffects - Run LayoutEffects - 瀏覽器paints畫面 - cleanup Effects - Run Effects ## Unmount - cleanup LayoutEffects - cleanup Effects # Memo: 避免不必要的re-render ```javascript= import { memo } from 'react' const Button = ({ onClick, children }) => { console.log('rerender button') return ( <button onClick={onClick} > {children} </button> ) } const MemoButton = memo(Button) ``` - input值變動時,MemoButton不會re-render ```jsx= <input type="text" placeholder='enter something...' value={value} onChange={handleChange} /> <MemoButton onClick={handleClick} > do button </MemoButton> ``` ## useCallback - 以下範例,input 與 button無關時,input值有變動,button不要re-render ```jsx= import useButton from '@/hooks/useButton' const Button = ({ onClick, children }) => { console.log('rerender button') return ( <button onClick={onClick} > {children} </button> ) } const MemoButton = memo(Button) function App() { const { value, handleChange } = useInput() const { textValue, handleClick } = useButton() return ( <div className="App"> <input type="text" placeholder='enter something...' value={value} onChange={handleChange} /> <div>{value}</div> <hr /> <MemoButton onClick={handleClick} > do button </MemoButton> <div>Button text: {textValue}</div> </div> ) } ``` ```jsx= import { useState, useCallback } from 'react' export default function useButton() { const [textValue, setTextValue] = useState('') const handleClick = useCallback(() => { setTextValue('kerker' + textValue) }, [textValue, setTextValue]) return { textValue, handleClick, } } ``` ### 避免re-render: useMemo ```jsx= const s = useMemo(() => { return value ? greenStyle : redStyle }, [value]) ```