React
名詞
web component : Web Components is a suite of different technologies allowing you to create reusable custom elements
JSX : 是一個 JavaScript 的語法擴充, 允許我們在 JS 的檔案中使用 HTML 的標籤
Virtual DOM :
Reconciliation : 找出哪些樹節點哪些需要變化
Immutability : 不可變性
Mutation : 修改
JSON Web Token (JWT) : 用來在 身份提供者 和 服務提供者 間傳遞被 認證 的用戶身份訊息,以便於從資源伺服器獲取資源
常用 list
- useState : react 使用的 state, 更動後就會 re-render
 - useEffect : 可控制 render 後要做什麼
 - useLayoutEffect : 可控制 render 前要做什麼
 - useRef : 近似於 useState,但更動後不會 re-render
 - memo : 把 component 包起來, 雖然 parents rerender 但本身未改變就不 rerender
 - useMemo : 把 data 記起來,未改變就不產生新的
 - useCallback : 把 function 記起來,未改變就不產生新的
 - useContext : 資料跨多層傳送
 - react router : 處理網頁的 route
 - useParams : 取得網頁的資訊
 - useHistory : 控制網頁跳頁
 - styled components : 方便輸入 css
 - ThemeProvider : set for theme
 - Link : 近似於 a tag
 - useLocation : 取得 path name
 - Fragment : 一個 component 讓你一次 render 多個 element 而不需要額外的 wrapper
 - useReducer : 可執行 dispatch
 
todolist simulate
1  | 
  | 
基礎
注意事項
- Component 的字首須為大寫字母 : 小寫字母開頭的組件視為原始 DOM 標籤
 
install and start
1  | # install  | 
Strict Mode and measuring performance
1  | import { StrictMode } from "react";  | 
export and export default
一個js只有一個回傳值,用export default, 有多個回傳值就用export
1  | // ./src/redux/reducers/index.js  | 
1  | // ./src/redux/actionTypes.js  | 
1  | // ./src/redux/actions.js  | 
1st React - include Inline styling
1  | // index.js  | 
1  | // App.js  | 
1  | /* App.css */  | 
styled components
install
1  | npm install styled-components  | 
Example 1
- styled-compoents 代替 function
 - 可以包下一層, set hover
 
1  | // App.js  | 
Example 2
- & + & (相連之 component)
 - 傳入props
 - TodoItem 移出成為一個 component
 
1  | // App.js  | 
Example 3
- media query  
1
2
3${MEDIA_QUERY_MD} {
font-size: 16px;
} - re-styled  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import TodoItem from './TodoItem'
// 對原本存在 function,再做 re-styled
const BlackTodoItem = styled(TodoItem)`
background: black;
`
function App() {
return (
<div className="App">
<TodoItem content="123"/>
<TodoItem content="456" size="XL"/>
<BlackTodoItem content="456" size="XL"/>
</div>
);
} - theme : 使用 ThemeProvider 內層可用 props 取用
 - TodoItem component 另存一個 file
 
index.js
1  | // index.js  | 
App.js
1  | // App.js  | 
./constants/style.js
1  | /* ./constants/style.js */  | 
TodoItem.js
1  | // TodoItem.js  | 
Example 4 - 對原本存在 function,再做 re-styled
1  | import React from 'react'  | 
JSX to react by Babel example
- JSX Prevents Injection Attacks
 - dangerouslySetInnerHTML
 - tag a run javascript: add encode URI
1
2
3{/* javascript:alert(1) */}
{/* <a href={todo.content}>click me</a> */}
<a href={window.encodeURIComponent(todo.content)}>click me</a> 
1  | <button size="XL">hello!</button>  | 
1  | <button size="XL" onClick={()=> {alert(1)} }>hello!</button>  | 
1  | <button size="XL" onClick={()=>{alert(1)} }><div>hello!</div></button>  | 
State
example 1
- state init : const [counter, setCounter] = React.useState(0);
 - state ange : setCounter(counter + 1)
 - ui upadte : counter: {counter}
 
1  | // App.js  | 
example 2 - 多欄位
1  | import React, { useState } from "react";  | 
example 3 - todos
- key
 - setTodos for array
 - todos.map
 
1  | // App.js  | 
example 4 - todos add item
- controlled component
 - uncontrolled component #1
 - uncontrolled component #2 (Ref)
 - todo change to object
 
App.js
1  | // App.js  | 
TodoItem.js
1  | // TodoItem.js  | 
example 5 - todos delete
- todo delete
 
App.js
1  | // App.js  | 
TodoItem.js
1  | // TodoItem.js  | 
example 6 - todos change state
- todo change state
 
App.js
1  | // App.js  | 
TodoItem.js
1  | // TodoItem.js  | 
useEffect
- render 後,你想做什麼
 
exampl 1 - add useEffect
1  | // add useEffect-1  | 
exampl 2 - run useEffect when todos change
1  | // save to localStorage after update-1+  | 
exampl 3 - run useEffect 1st render
1  | // App.js  | 
exampl 4 - set local storage to init todos
1  | // App.js  | 
exampl 5 - clear up LayoutEffects
1  | // App.js  | 
改寫成自己的 hook
App.js
1  | // App.js  | 
useInput.js
1  | // useInput.js  | 
useTodos.js
1  | // useTodos.js  | 
memo, useMemo, useCallback
- memo - 把 component 包起來, 雖然 parents rerender 但本身未改變就不 rerender
1
2
3// add memo - 傳入不變,即不 re-render
// 但每次 render 會 new handleTodosClick
const MemoButton = memo(Button); - useMemo - 把 data 記起來,未改變就不產生新的
1
2
3
4
5
6// add useMemo - for data
// todos change no run
const s = useMemo(() =>{
console.log('calculate s')
return value ? redStyle : blueStyle;
}, [value]) - useCallback - 把 function 記起來,未改變就不產生新的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// add useCallback - [] 表沒東西會造成改變
const handleTodosClick = useCallback(() =>{
console.log(value);
// set input value
setTodos([{
id: id.current,
content: value,
isDone: false
}, ...todos])
setValue('')
// use ref
id.current++
}, [setValue, value, todos]); 
1  | // App.js  | 
1  | // useTodos.js  | 
lazy initializer - useState() 加 function 僅第一次執行
1  | // App.js  | 
useLayoutEffect
- render 前你想做什麼
 
exampl 1
1  | // App.js  | 
class component
example 1
1  | // App.js  | 
1  | // TodoItem.js  | 
example 2 - class component lifeCycle 生命週期
- PureComponent : same as memo(props 有變動才update)
 - shouldComponentUpdate : return false not update
 - componentDidMount : mount
 - componentDidUpdate : update
 - componentWillUnmount : before unmount(not render the component)
 
1  | // index.js  | 
1  | // Counter.js  | 
useContext
prop Drilling : 資料跨多層傳送
1  | // index.js  | 
1  | // Demo.js  | 
useContext example 1
./App.js
1
2
3
4
5
6
7
8
9
10
11// ./App.js
import React from "react";
import ContentExample from "./ContentExample";
export default function App() {
return (
<div>
<ContentExample />
</div>
);
}./ContentExample
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31// ./ContentExample
import React, { createContext, useContext } from "react";
const slogan = "super star";
const Content = createContext();
function SideBarButton(props) {
// get context
const title = useContext(Content);
return <div>{title}</div>;
}
function SideBar(props) {
// get context
const bt = useContext(Content);
return (
<div>
<button>{bt}</button>
<SideBarButton />
</div>
);
}
export default function ContentExample(props) {
return (
// set Context
<Content.Provider value={slogan}>
<SideBar />
</Content.Provider>
);
}useContext example 2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// add useContext(also import createContext )
import { useState, useContext, createContext } from "react";
const ColorContext = createContext()
function DemoInnerBoxContent() {
// 取出 colors
const colors = useContext(ColorContext)
}
return (
// colors 透過 createContext 傳送
<ColorContext.Provider value={colors} >
......
</ColorContext.Provider>
)useContext for array
useContext 可動態改變
useContext 中間層可改變
1  | // index.js  | 
1  | // Demo.js  | 
propTypes 驗證 props
1  | # 雖然 create-react-app 已安裝, 建議要安裝(因為 React 隨時都有可能更新內部 dependency 的版號,甚至移除 node module)  | 
add file ./.eslintrc.json
1  | {  | 
1  | // App.js  | 
1  | // TodoItem.js  | 
1  | // useTodos.js  | 
deployment
local
1  | # build  | 
deploy to github
add scripts and homepage
package.json
1  | "scripts": {  | 
insatll gh-pages
1  | npm install --save gh-pages  | 
github add repository - react-comments-test2
deploy to github
1  | # git init and commit  | 
open by browser
https://hot5656.github.io/react-comments-test2/
react router
install
1  | npm install react-router-dom  | 
useParams
1  | // ./Pages/BlogPost/BlogPost.js  | 
useHistory, useLocation
1  | import { Link, useLocation, useHistory } from "react-router-dom";  | 
example #1
./component/App
1  | // ./component/App/App.js  | 
1  | // ./component/App/index.js  | 
./component/Header
1  | // ./component/Header/Header.js  | 
1  | // ./component/Header/index.js  | 
./Pages/HomePage
1  | // ./Pages/HomePage/HomePage.js  | 
1  | // ./Pages/HomePage/index.js  | 
./Pages/LoginPage
1  | // ./Pages/LoginPage/LoginPage.js  | 
1  | // ./Pages/LoginPage/index.js  | 
react event
- onClick
 - onChange
 - onBlur : 離開表單
 
prettier ESLint
create-react-app default include ESLint configuration
.\node_modules\react-scripts\config\webpack.config.js
1  | !disableESLintPlugin &&  | 
vscode ESlint configuration - ESLint
./.eslintrc.json
1  | {  | 
prettier - Prettier - Code formatter (Prettier)
settings.json
1  | {  | 
1  | # 雙引號  | 
測試
react-testing-library : 測試 React component
Cypress : end ot end test
Developer Tools
- React Developer Tool
 - Storybook
 - Bundle Analyzer
 - Why Did You Render
 - React Testing Library With Jest
 - Formik and Yup
 - React Hook Form
 - React Sight
 - React Proto
 
參考資料
- styled components
 - tagged template
 - Babel is a JavaScript compiler
 - Prettier
 - React Setting Up Your Editor
 - Introducing JSX
 - dangerouslySetInnerHTML
 - hook-flow
 - A Complete Guide to useEffect
 - useLocalStorage
 - 從頭打造一個簡單的 Virtual DOM
 - 為了瞭解原理,那就來實作一個簡易 Virtual DOM 吧!
 - React lifeCycle 生命週期
 - react deployment
 - react router
 - JWT
 - react-testing-library
 - cypress
 - 從零開始學 ReactJS(ReactJS 101)
 - Overreacted(Dan Abramov)
 - ReactDOMServer : SSR reffence
 - PRERENDER io : SSR reference
 - *** Next.js : The React Framework for Production (內建 SSR)
 - TypeScript: .ts, JavaScript 加型態, 需編譯後才能執行
 - React Interview Questions & Answers