HackMD
  • Prime
    Prime  Full-text search on all paid plans
    Search anywhere and reach everything in a Workspace with Prime plan.
    Got it
      • Create new note
      • Create a note from template
    • Prime  Full-text search on all paid plans
      Prime  Full-text search on all paid plans
      Search anywhere and reach everything in a Workspace with Prime plan.
      Got it
      • Options
      • Versions and GitHub Sync
      • Transfer ownership
      • Delete this note
      • Template
      • Save as template
      • Insert from template
      • Export
      • Dropbox
      • Google Drive
      • Gist
      • Import
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
      • Download
      • Markdown
      • HTML
      • Raw HTML
      • Sharing Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • More (Comment, Invitee)
      • Publishing
        Everyone on the web can find and read all notes of this public team.
        After the note is published, everyone on the web can find and read this note.
        See all published notes on profile page.
      • Commenting Enable
        Disabled Forbidden Owners Signed-in users Everyone
      • Permission
        • Forbidden
        • Owners
        • Signed-in users
        • Everyone
      • Invitee
      • No invitee
    Menu Sharing Create Help
    Create Create new note Create a note from template
    Menu
    Options
    Versions and GitHub Sync Transfer ownership Delete this note
    Export
    Dropbox Google Drive Gist
    Import
    Dropbox Google Drive Gist Clipboard
    Download
    Markdown HTML Raw HTML
    Back
    Sharing
    Sharing Link copied
    /edit
    View mode
    • Edit mode
    • View mode
    • Book mode
    • Slide mode
    Edit mode View mode Book mode Slide mode
    Note Permission
    Read
    Owners
    • Owners
    • Signed-in users
    • Everyone
    Owners Signed-in users Everyone
    Write
    Owners
    • Owners
    • Signed-in users
    • Everyone
    Owners Signed-in users Everyone
    More (Comment, Invitee)
    Publishing
    Everyone on the web can find and read all notes of this public team.
    After the note is published, everyone on the web can find and read this note.
    See all published notes on profile page.
    More (Comment, Invitee)
    Commenting Enable
    Disabled Forbidden Owners Signed-in users Everyone
    Permission
    Owners
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Invitee
    No invitee
       owned this note    owned this note      
    Published Linked with GitHub
    Like BookmarkBookmarked
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # [FE302] React 基礎:hooks(1) [TOC] ## [FE302] 2. React 基礎 ## [FE302] 2-1 [環境建置——Create react app](https://zh-hant.reactjs.org/docs/create-a-new-react-app.html) ### 現成線上環境:CodeSandBox 優點:debug 分享方便 缺點: ### 在自己電腦上建置環境 :::info 自己建置環境:webpack、React、Babel 現成建置環境:npm modules -- Create-react-app ::: 1. 已安裝 Node version >= 10.16 2. 已安裝npm version >= 5.6 3. 安裝 npm 套件 —— Create react app ```bash= npx create-react-app my-app // create-react-app -v # 查看版本有無安裝完成 cd my-app npm start # 或 npm run build # 啟動 dev server Compiled successfully! You can now view my-app in the browser. Local: http://localhost:3000 On Your Network: http://xxx.xxx.x.xxx:3000 Note that the development build is not optimized. To create a production build, use yarn build. ``` ### 一拿到專案,先看 `README.md`,再看`package.json` 環境建置起來後(可以從 `localhost:3000`看到) :::warning 專案拿到的一開始,先看 `README.md`,再看`package.json` ::: * `README.md` ```bash= yarn start # yarn 跟 npm 一樣,只是 yarn 比 npm 快 ``` * `package.json` 可以看用哪些 npm、測試怎麼使用 ```json= { "name": "my-app", "version": "0.1.0", "private": true, "dependencies": { // 使用些測試 "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.1.0", "@testing-library/user-event": "^12.1.10", "react": "^17.0.2", "react-dom": "^17.0.2", "react-scripts": "4.0.3", // create-app 主要的東西 "web-vitals": "^1.0.1" }, "scripts": { // 包好套件,方便執行一些檔案 "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, "eslintConfig": { "extends": [ "react-app", "react-app/jest" ] }, "browserslist": { // 支援的 browser "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } } ``` ### 開啟 `./src/index.js` 前面環境建置好後,就可以開始寫 react app: ```javascript= import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; // step2: 從下面 render app 然後去找 app 從哪來。 import reportWebVitals from './reportWebVitals'; //和網站效能有關 ReactDOM.render( <React.StrictMode> // 嚴格模式,會幫我們檢查一些不該用的東西。 // 但是會影響 console.log() 所以通常都沒有使用 <App /> // step1: render App 這個 component </React.StrictMode>, document.getElementById('root') ); // If you want to start measuring performance in your app, pass a function // to log results (for example: reportWebVitals(console.log)) // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals reportWebVitals(); ``` 發現 `<App />` 這個 component 從 `./App.js` 引入,所以就來看看這個檔案: 可以發現在 `http://localhost:3000` 的網頁內容來自此處,可以相對應修改,然後在 `http://localhost:3000` 會做相應改變。 ```javascript= import logo from './logo.svg'; import './App.css'; function App() { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p> Edit <code>src/App.js</code> and save to reload save to reload save to reload save to reload save to reload . </p> <a className="App-link" href="https://reactjs.org" target="_blank" rel="noopener noreferrer" > Learn React </a> </header> </div> ); } export default App; ``` ![](https://i.imgur.com/TJ81PRQ.png) 嘗試修改 `app.js`,再觀察 localhost:3000 及 terminal: * `app.js` ```javascript= import logo from './logo.svg'; import './App.css'; function App() { return ( <div className="App"> hello world!! </div> ); } export default App; ``` * `http:localhost:3000` ![](https://i.imgur.com/Twbisek.png) * terminal 因為在 create-react-app 有預設 ESLint,所以 ESLint 的 warning & 提示都會在 terminal 出現。 ```bash= Compiled with warnings. src/App.js Line 1:8: 'logo' is defined but never used no-unused-vars Search for the keywords to learn more about each warning. To ignore, add // eslint-disable-next-line to the line before. ``` ### 建立 component 1. 建立一個 component by function,名字為 `Title` * 在 React,component 名字以大寫鴕峰為命名慣例。 * `return(內容)` 在 React 中,可以以 `()` 括號包起來 * 將新建好的 component 放入 App() 裡面,放入的是 `<Title />` 如果沒有要輸入任何參數,直接 `/>` 關起來即可。 ``` import logo from './logo.svg'; import './App.css'; function Title() { return ( <h1>hello World!!!</h1> ) } function App() { return ( <div className="App"> <Title /> </div> ); } export default App; ``` #### component 內沒有參數輸入 1. `props.children` ```javascript= import logo from './logo.svg'; import './App.css'; function Title() { return ( <h1>hello World!!!</h1> ) } + function Description(props) { + return ( + <p> + {props.children} + </p> + ) + } function App() { return ( <div className="App"> <Title /> + <Description> + hihihihihihihihi + </Description> </div> ); } export default App; ``` ![](https://i.imgur.com/XQw6E0A.png) 2. 解構賦值 ```javascript= import logo from './logo.svg'; import './App.css'; function Title() { return ( <h1>hello World!!!</h1> ) } + function Description({children}) { + return ( + <p> + {children} + </p> + ) +} function App() { return ( <div className="App"> <Title /> <Description> hihihihihihihihi </Description> </div> ); } export default App; ``` ## [FE302] 2-2 初探 React 中的 style :::info 有三種方法: 1. `import './App.css'` 2. inline-style 3. styled-component ::: ### 2-2-1. `import './App.css'` 像之前的用法一樣,引入 CSS ,然後就可以使用 ### 2-2-2. inline-style #### 2-2-2-1 React 寫 CSS:inline-style 一:寫在 `style` 內 :::success 補充: 直接在 JSX 內的 HTML 標籤內加入 style 屬性(如:style={}),但有幾點需要注意: 1. JSX 中的 inline style 要放入 object(物件),在 JSX 中只要和 JS 有關的參數,都要加上`{}`(style=`{}`的外層大括號) 3. 只能傳入該元素支援的 inline-style 4. 不能使用「偽元素(`after`)」或「`hover`」 6. 因為是 JavaScript 程式碼,需改為小寫駝峰命名(例如:`titleStyle`) React CSS 建立的 object 命名慣例為:小寫鴕峰。 ::: 在 React 寫一個 Object 名字為 titleStyle。然後在 React 內的 JSX 中有一個屬性為 `style` 專門寫 CSS 的內容,可以使用兩個方法寫 CSS: 1. `<h1 style={<CSS 的 object>}`:直接另外新增個 CSS object,然後以 `{}` 放入。(在 JSX,只要和 JS 有關的,放進去都要以`{}`包起來) ```react= const titleStyle = { color: 'red', textAlign: 'center' } function Title({ size }) { if (size === 'XL') { return <h1>hello</h1> } return ( <h1 style={titleStyle}>hello</h1> ) } ``` 2. `<h1 style={{ height: '10%' }}`:外層大括號為要傳入的參數(JSX 語法),內層為要傳入的 object (大括號)。 ```react= const titleStyle = { color: 'red', textAlign: 'center' } function Title({ size }) { if (size === 'XL') { return <h1>hello</h1> } return ( <h1 style={{ color: 'red', textAlign: 'center' }}>hello</h1> ) } ``` #### 2-2-2-2 React 寫 CSS:inline-style 二:寫在 `className` 內 :::success 為什麼不能用 class? 在 JSX 語法很特別的原因是不能直接傳 class,因為 `class` 在 JavaScript 是保留字,所以不希望用 `class`,所以改用 `className`, ::: #### 2-2-3 [`styled-component`](https://styled-components.com/docs/basics#getting-started) :::info syntax ```react= const Title = styled.h1` font-size: 1.5em; text-align: center; color: palevioletred; `; ``` &#96;&#96; 是 [template literals(樣版字面值)](https://pjchender.blogspot.com/2017/01/javascript-es6-template-literalstagged.html),也可以當成 `function code` 使用, ::: ##### 安裝 ``` # with npm npm install --save styled-components # with yarn yarn add styled-components ``` ##### import 套件 ```react= import styled from 'styled-components'; ``` ##### 示範 ```react= import React from 'react'; import logo from './logo.svg'; import './App.css'; // 因為 webpack 所以可以直接 import css + import styled from 'styled-components'; function Title({ size }) { if (size === 'XL') { return <h1>hello</h1>; } return ( <h2 style={{ display: 'flex', color: 'red', textAlign: 'center', }}>hello</h2> ) } + const Description = styled.p` + color: red; + padding: 20px; + border: 1px solid black; + ` function App() { const titleSize = 'M' return ( <div className="App"> <Title size={titleSize} /> <Description> 衷心感謝 </Description> </div> ) } export default App; ``` ![](https://i.imgur.com/9GUQ71J.png) 可以發現:`Description` 這個 component 會預設 className(HOBA-D),這個 className 就是 `style-component` 幫我加的。 原理:動態產生 className ,然後動態產生 CSS 放在 HTML tag 上。 ##### 示範 2 將 `Title` 也改成 `styled-component`, ```react= const TitleWrapper = styled.h2` // component 是大寫鴕峰,開投藥大寫。 display: flex; // 像一般 CSS 的寫法 color: blue; &:hover { # 也可以使用 sass 語法 color: red; } span { # 更可以寫子層次的格式。 color: yellow; } ` function Title({ size }) { return ( <TitleWrapper>hello<span>yes</span></TitleWrapper> ) } ``` ![](https://i.imgur.com/G0XN2m9.png) 滑鼠移過去變成紅色,hover 效果。 ##### 實做 todolist `styled-component` 會自己加 prefix 不用擔心有網路兼容性問題 ```react= import React from 'react'; import logo from './logo.svg'; import './App.css'; // 因為 webpack 所以可以直接 import css import styled from 'styled-components'; const TodoItemWrapper = styled.div` display: flex; align-items: center; justify-content: space-between; padding: 8px 16px; border: 1px solid black; ` const TodoContent = styled.div` color: black; ` const TodoButtonWrapper = styled.div`` const Button = styled.button` padding: 4px; color: black; & + & { margin-left: 4px; } :hover { color: white; background: blue; } ` // button + button 也就是第二個 function App() { const titleSize = 'M' return ( <div className="App"> <TodoItemWrapper> <TodoContent>I am todo</TodoContent> <todoButtonWrapper> <Button>編輯</Button> <Button>刪除</Button> </todoButtonWrapper> </TodoItemWrapper> </div> ) } export default App; ``` ![](https://i.imgur.com/rUSJHi3.png) ##### `styled-component` 也可以加入 `props` (properties 屬性) ```react= <!-- 方法一:三元運算子 --> const TodoContent = styled.div` color: black; + font-size: ${props => props.size === 'XL' ? '20px' : '12px'} ` <!-- 可以使用 JS 的語法,像是 `${}` 一樣, 一般在裡面會加個箭頭函式,然後 parameters 為 props。 使用三元運算子,如果是 'XL',就顯示 20px,如果不是,就顯示 12px。 --> <!-- 方法二:短路的概念 --> const TodoContent = styled.div` color: black; font-size: 12px; ${props => props.size === 'XL' && ` font-size: 20px; `} ` <!-- 利用短路的概念,當 `props.size === 'XL'` 符合時 就會執行下一個, 然後就會覆蓋掉 font-size:12px,使用 `20px` --> function App() { const titleSize = 'M' return ( <div className="App"> <TodoItemWrapper> + <TodoContent size="XL">I am todo</TodoContent> <todoButtonWrapper> <Button>編輯</Button> <Button>刪除</Button> </todoButtonWrapper> </TodoItemWrapper> </div> ) } ``` ![](https://i.imgur.com/2qfI8AL.png) 一般會將重複的再寫成一個 component: ```react= const TodoItemWrapper = styled.div` display: flex; align-items: center; justify-content: space-between; padding: 8px 16px; border: 1px solid black; width: 60%; + & + & { + margin-top: 12px; + } ` + + const TodoItem = function ({ size, content }) { + <!-- function TodoItem({ size, content }) { 非箭頭函式--> + <!-- const TodoItem = ({ size, content }) => { 箭頭函式--> + return ( + <TodoItemWrapper> + <TodoContent size={size}>{content}</TodoContent> + <todoButtonWrapper> + <Button>編輯</Button> + <Button>刪除</Button> + </todoButtonWrapper> + </TodoItemWrapper> + ) + } function App() { const titleSize = 'M'; return ( <div className="App"> <TodoItem content={123}></TodoItem> <TodoItem content={456} size='XL'></TodoItem> </div> ) } ``` ![](https://i.imgur.com/RswCeDm.png) ## [FE302] 2-2 styled component 實戰 :::info 此章節介紹比較進階,在切版時會用到的用法: 推薦官方文件: [`Styled-component Basics`](https://styled-components.com/docs/basics) ::: ### 2-2-1 第一個常用的:Restyle ```react= + const RedButton = styled(Button)` + color: red; + ` function TodoItem({ size, content }) { return ( <TodoItemWrapper> <TodoContent size={size}>{content}</TodoContent> <todoButtonWrapper> <Button>編輯</Button> <RedButton>刪除</RedButton> </todoButtonWrapper> </TodoItemWrapper> ) } function App() { const titleSize = 'M'; return ( <div className="App"> <TodoItem content={123}></TodoItem> <TodoItem content={456} size='XL'></TodoItem> </div> ) } ``` Restyle,在原本的 `Button` component 上再加上 CSS 放在刪除按鈕上: ![](https://i.imgur.com/cJeq2vA.png) 如果今天想加上 `<TodoItem>` 的黑色背景: ```React= function TodoItem({ size, content }) { return ( <TodoItemWrapper> <TodoContent size={size}>{content}</TodoContent> <todoButtonWrapper> <Button>編輯</Button> <RedButton>刪除</RedButton> </todoButtonWrapper> </TodoItemWrapper> ) } + const BlackTodoItem = styled(TodoItem)` + background: black; + ` ``` 背景底色沒有變,因為 `styled-component` 背後的原理是透過傳 `ClassName` ![](https://i.imgur.com/RRifqgx.png) 所以要在原本的 `Component` 傳入一個參數 `{className}`,然後把這個 `{className}` 放在想放的地方: ```react= + function TodoItem({ className, size, content }) { return ( + <TodoItemWrapper className={className}> <TodoContent size={size}>{content}</TodoContent> <todoButtonWrapper> <Button>編輯</Button> <RedButton>刪除</RedButton> </todoButtonWrapper> </TodoItemWrapper> ) } + const GreyTodoItem = styled(TodoItem)` + background: grey; + ` function App() { const titleSize = 'M'; return ( <div className="App"> <TodoItem content={123}></TodoItem> + <GreyTodoItem content={456} size='XL'></GreyTodoItem> </div> ) ``` 變成說某一個 `GreyTodoItem` 變成某一個 class 有這個 `background: grey;`,然後再看要把這個 class 給誰,這邊示範是給 `ItemWrapper`。 也可對象為 `styled-component`,直接如上方寫即可,他會直接處理好;也可以對一般的 `component` 做一樣的事情(傳入`{className}`), ![](https://i.imgur.com/u25ipfS.png) ### 2-2-2 第二個常用的:Media Queries (MQ) :::info 通常習慣從 mobile 寫起,先看 mobile 版面,參考[W3 School: Media Queries](https://www.w3schools.com/css/css3_mediaqueries_ex.asp) ::: ```react= const Button = styled.button` padding: 4px; color: black; font-size: 20px; + @media screen and (min-width: 768px) { + font-size: 16px; + } & + & { margin-left: 4px; } :hover { color: white; background: blue; } ` ``` 從手機版變到平版(最小 768 px)時,字體會從 `20px` 變成 `16px`。 ![](https://i.imgur.com/CHXjxce.png) ![](https://i.imgur.com/4IlNin8.png) :::success 但是每個 component 都要加上 MQ(Media Queries),很麻煩,通常會建立一個 `constants/constants.js` 常數名稱的資料夾。 ``` |-- src | -- App.js | -- index.js | -- constants | -- style.js ``` ::: * `style.js` ```react= <!-- style.js --> export const MEDIA_QUERY_MD = '@media screen and (min-width: 768px)' export const MEDIA_QUERY_LG = '@media screen and (min-width: 1024px)' ``` * App.js ```react= <!-- App.js --> + import { MEDIA_QUERY_MD, MEDIA_QUERY_LG } from './constants/style' const Button = styled.button` padding: 4px; color: black; font-size: 20px; + ${MEDIA_QUERY_MD} { + font-size: 16px; + } + ${MEDIA_QUERY_LG} { + font-size: 12px; + } & + & { margin-left: 4px; } :hover { color: white; background: blue; } ` ``` ![](https://i.imgur.com/LdniHsS.png) ### 2-2-3 [Advanced](https://styled-components.com/docs/advanced):theming :::info 1. 提供傳一個 `global` 的參數,在 `App.js` 就能用到。 2. 以 `theme` 傳遞變數的功能,來達到我們之前寫 SASS 的變數功能。 3. 好處: 可以調整主色,如果哪天想要調整主題色,就可以使用這個來調整主題色,從主題色紅色改藍色等等。 ```react= const theme = { colors: { primary_300: '#e61111', primary_400: '#440000', primary_500: '#660000' } } ``` ::: * index.js 使用 `<ThemeProvide theme={theme}>` ,傳入 `global` 參數: 然後另外設 object,代入如下一段 code(`App.js`) ```react= import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; //和網站效能有關 + import { ThemProvider } from 'styled-components'; + const theme = { + colors: { + red_300: '#e61111', + red_400: '#440000', + red_500: '#660000' + } + } ReactDOM.render( + <ThemProvider theme={theme}> <App /> + </ThemProvider>, + document.getElementById('root') ); ``` * App.js 透過 `index.js` 的 `<ThemeProvider theme={theme}>` 傳入的 `theme` 變數: :::warning 記得在 CSS 每個後面加分號,不然會沒有效果。 ::: ```react= const TodoContent = styled.div` + color: ${props => props.theme.colors.red_300}; font-size: 12px; ${props => props.size === 'XL' && ` font-size: 20px; `} ` ``` ![](https://i.imgur.com/ePZkZZU.png) :::info styled-component 1. theme 2. restyle 3. media-Query 可以透過參數來寫的方式 需要的也可以去官方網站補充 如果後面切版太多 component,可以另建檔案,把 component 獨立出來: `export default function TodoItem() {}` ::: 範例: 將 App.js 分開,拆到 `TodoItem.js` * index.js ```react= import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import reportWebVitals from './reportWebVitals'; // 和網站效能有關 + import { ThemeProvider } from 'styled-components'; const theme = { colors: { red_300: '#e61111', red_400: '#440000', red_500: '#660000' } } ReactDOM.render( <ThemeProvider theme={theme}> <App /> </ThemeProvider>, document.getElementById('root') ); reportWebVitals(); ``` * App.js ```react= import React from 'react'; import logo from './logo.svg'; import './App.css'; // 因為 webpack 所以可以直接 import css import styled from 'styled-components'; import { MEDIA_QUERY_MD, MEDIA_QUERY_LG } from './constants/style' import TodoItem from './TodoItem' const GreyTodoItem = styled(TodoItem)` background: grey; ` function App() { const titleSize = 'M'; return ( <div className="App"> <TodoItem content={123}></TodoItem> <GreyTodoItem content={456} size='XL'></GreyTodoItem> </div> ) } export default App; ``` * TodoItem.js ```react= import React from 'react'; import logo from './logo.svg'; import './App.css'; // 因為 webpack 所以可以直接 import css import styled from 'styled-components'; import { MEDIA_QUERY_MD, MEDIA_QUERY_LG } from './constants/style' const TodoItemWrapper = styled.div` display: flex; align-items: center; justify-content: space-between; padding: 8px 16px; border: 1px solid black; & + & { margin-top: 12px; } ` const TodoContent = styled.div` color: ${props => props.theme.colors.red_300}; font-size: 12px; ${props => props.size === 'XL' && ` font-size: 20px; `} ` //JS 放 function 一般放 arrow func,一般用 props, const TodoButtonWrapper = styled.div`` const Button = styled.button` padding: 4px; color: black; font-size: 20px; ${MEDIA_QUERY_MD} { font-size: 16px; } ${MEDIA_QUERY_LG} { font-size: 12px; } & + & { margin-left: 4px; } :hover { color: white; background: blue; } ` const RedButton = styled(Button)` color: red; ` // button + button 也就是第二個 + export default function TodoItem({ className, size, content }) { return ( <TodoItemWrapper className={className}> <TodoContent size={size}>{content}</TodoContent> <todoButtonWrapper> <Button>編輯</Button> <RedButton>刪除</RedButton> </todoButtonWrapper> </TodoItemWrapper> ) } ``` ## [FE302] 2-3 [一探 JSX 背後的秘密] 為什麼可以使用 `return()`,就建立起來了呢? ```react= export default function TodoCard({ content }) { return ( <TodoItem> <TodoContent> <IconUnchecked /> <TodoText>{content}</TodoText> </TodoContent> <TodoButtonWrapper> <IconEdit /> <IconDelete /> </TodoButtonWrapper> </TodoItem> ) } ``` 背後其實是通過 Babel 轉換而來: * React ```react= <TodoList content='Todo 1'>Hello</TodoList> ``` * Babel ```javascript= /*#__PURE__*/ React.createElement(TodoList, { content: "Todo 1" }, "Hello"); /* React.createElement(TodoList, { content: "Todo 1" -> props }, "Hello"); --> 文字內容 */ ``` 試試看 使用被 Babel 轉成的 JS: 示意: ```javascript= <TodoList content='Todo 1'>Hello</TodoList> // 等同於:以下 { React.createElement(TodoList, { content: "Todo 1" }, "Hello"); } ``` :::success 其實是一個 function,把 `object`、`children`、 ::: 另外如果 childredn 裡面是另外一個 component 的話: * React ``` <TodoList content='Todo 1'><div>hello</div>Hello</TodoList> ``` * Babel 將 React 語法轉成 JS 再在裡面做一次 `React.createElement()` ```javascript= /*#__PURE__*/ React.createElement(TodoList, { content: "Todo 1" }, /*#__PURE__*/React.createElement("div", null, "hello"), "Hello"); ``` :::warning 在 React 17 以前: 每個有使用到 `JSX` 的地方,都要 `import React from 'react';`,因為他會使用到 `React.createELement()` 的語法,不然會壞掉 在 React 17 之後: Babel 會幫我們做 ::: ## [FE302] 2-4 [初探 State] :::success UI 只是 State 的 mapping。 畫面永遠由 state 產生。 ### `UI = f(state)` ![](https://i.imgur.com/0fM6JNV.png) ::: :::info 在 React 要使用 State,需要引入 React modules。 `React.useState()` 的 `state` 就是一個 `hook`。 ← React 16.8 → 才出現 hooks,在 function component 使用 `state` syntax: ```react= import React from 'react'; const [counter, setCounter] = React.useState(`<初始值>`) <!-- 為解構語法,回傳一個陣列,counter 為 state 的值,第二個為 setCounter,如何去 set state。--> <!-- 解釋這個解構語法--> function useState() { return [counter, setCounter] } ``` :::warning 在 component 中,有兩種: 1. function component 2. class component ::: ### 試試看做一簡單的 state 點擊後會增加次數 點擊 `increment` 按鈕後,會實行 `handleButtonClick` 的 function,也就是會執行`SetCounter(counter + 1)`,然後在畫面上的 `counter:` 顯示數字會+1。 ```react= function App() { + const [counter, setCounter] = React.useState(0) + function handleButtonClick(e) { + setCounter(counter + 1) + } const titleSize = 'M'; return ( <div className="App"> + counter: {counter} <TodoItem content={123}></TodoItem> + <button onClick={handleButtonClick}>increment</button> <GreyTodoItem content={456} size='XL'></GreyTodoItem> </div> ) } ``` ![](https://i.imgur.com/U0jSQyR.png) 再點擊一次,變成+1,從 9 變成 10 ![](https://i.imgur.com/K20oDAG.png) 原理解釋: React 流程 1. 動作:執行 App() 這個 function,會 return JSX,React 會把這些 JSX 放到畫面上,這個動作就是 `mount`(瀏覽器 render 出來畫面) 2. 當 state 有更新時,就會 rerender(就是再 call 一次 App())。 以下圖解釋: ![](https://i.imgur.com/8DBlmxC.png) 1. 重整頁面,counter: 0 2. 按 increment 按鈕,此時 counter + 1 = 0 + 1(`setCounter(counter+1)`) 3. console ``` App.js:16 button click 當按鈕按下去時,就會重新執行 `App()` 所以才會出現 render 1 App.js:14 render 1 ``` 4. React 重新呼叫 App(),再 Render 一次,就是 Rerender。 ### useState 傳入陣列,再搭配 `.map()`,把每一個 array element render 成 component。 * 最開始,沒有講 state 概念時: ```react= function App() { const titleSize = 'M'; return ( <div className="App"> <button onClick={handleButtonClick}>Add todo</button> <TodoItem content={123}></TodoItem> <GreyTodoItem content={456} size='XL'></GreyTodoItem> </div> ) } ``` * 加入 state 概念,並使用陣列傳入 123, 456 ```react= function App() { const [todos, setTodos] = React.useState([ 123, 456 ]) // render 陣列 function handleButtonClick(e) { } const titleSize = 'M'; return ( <div className="App"> <button onClick={handleButtonClick}>Add todo</button> <!-- {} 為輸入 JavaScript 語法時需要 這個就是把兩個 todo 利用陣列([])的 component。 效果同上> --> { [<TodoItem content={123}></TodoItem>, <TodoItem content={456} size='XL'></TodoItem>] } </div> ) } ``` ![](https://i.imgur.com/erWQ38g.png) * `array.map()` react 沒有迴圈,只能用 map,好處是可以把每一個 array element map 成 component。就是可以 render 很多component。 所以在 React 如果要 render 一系列的資料,就會使用 `.map` 來做。 ```react= function App() { const [todos, setTodos] = React.useState([ 123, 456 ]) // render 陣列 function handleButtonClick(e) { } const titleSize = 'M'; return ( <div className="App"> <button onClick={handleButtonClick}>Add todo</button> // react 沒有迴圈,只能用 map,好處是可以把每一個 array element map 成 component。就是可以 render 很多component。 { todos.map(todo => <TodoItem content={todo} />) } ``` ![](https://i.imgur.com/FcPFA0b.png) 錯誤訊息: :::warning Warning: Each child in a list should have a unique "key" prop. ::: ```javascript= index.js:1451 Warning: Each child in a list should have a unique "key" prop. Check the render method of `App`. See https://reactjs.org/link/warning-keys for more information. at TodoItem (http://localhost:3000/static/js/main.chunk.js:264:3) at App (http://localhost:3000/static/js/main.chunk.js:119:74) at Fe (http://localhost:3000/static/js/0.chunk.js:43408:67) ``` 在使用 `.map()` 產生 `component` 時,需要產生 `key` 讓 `react` 去辨別是哪一個 item,先以`{index}` 為 key,但不推薦名稱命名為 `index`。 ```react= { + todos.map((todo, index)=> <TodoItem key={index} content={todo} />) } ``` #### 當 React 判定 old statue = new state,就不會更新 :::danger ## statue is immutable ::: #### 如何改 state? ``` function App() { const [todos, setTodos] = React.useState([ 123, 456, 555 ]) } const handleButtonClick = () => { // 如何改變 state? } ``` 1. todos.push(777) > 不能直接這樣改,要使用 `setTodos()` 改 2. todos.push(777); setTodos(todos) > 點選 「add todo」 沒有反應。 > 因為 > todos.push(777) //此時舊的 todos [123, 456, 55, 777] > setTodos(todos) //在 setTodos之後新的 todos [123, 456, 55, 777] > 當 React 判定舊的跟新的 state 一樣時,就表示 state 沒有更新,那就不會 rerencer。 > :::info > ### State Immutable > ::: 3. setTodos([...todos, 777]) // 前面加上 todos element,後面再加上新的值。 > ```react= > function App() { > const [todos, setTodos] = React.useState([ > 123, 456, 555 > ]) > function handleButtonClick(e) { > setTodos([...todos, Math.random()]) > <!-- > setTodos([Math.random(), ...todos]) --> > > <!-- state 改變(前後不一樣),會再 render 一次 --> > } > const titleSize = 'M'; > return ( > <div className="App"> > <button onClick={handleButtonClick}>Add todo</button> > { > todos.map(todo => <TodoItem content={todo} />) > } > </div> > ) > } > > export default App; > ``` > > ![](https://i.imgur.com/W0ZgBRT.gif) > > :::success > 不應該去修改 state (immutable, like todos) 的內容,應該是透過 `setTodos` 去修改內容,產生一個新的陣列,然後再 render 到頁面上。 > <br> > 另外,也可以改成: > `import {useState} from 'react';` > 直接解構 > ::: ## [FE302] 2-4 [再探 State] :::info state 分成兩種: 1. controlled:useState 2. uncontrolled ::: 複習 useState, ```react= import {useState} from 'react'; function App() { <!-- 1. 使用 useState,state 的值、如何改變 state 的值 --> const [todos, setTodos] = useState([ 123, 456, 555 ]) function handleButtonClick(e) { <!-- 2. 要改變時,需要 call setTodos 來改變 state 的值 --> setTodos([...todos, Math.random()]) } <!-- 3. state is immutabl,不能直接改,是要改的話,需要產生新的--> const titleSize = 'M'; return ( <div className="App"> <button onClick={handleButtonClick}>Add todo</button> { todos.map(todo => <TodoItem content={todo} />) } </div> ) } ``` ### controller component & uncontrolled #### 1. controlled state :::success ## 所有在 UI 上會動的東西 幾乎都是個state ::: ![](https://i.imgur.com/4SCujef.png) 其實在輸入 `qwer` 時,也會在 React 的 state,可以在自己的裡面控制。,如下範例的 ```react= function App() { + const [ value, setValue = useState('') return ( <div className="App"> + <input type='text' placeholder='new todo' value={value} /> <button onClick={handleButtonClick}>Add todo</button> { todos.map(todo => <TodoItem content={todo} />) } </div> ) } export default App; ``` ![](https://i.imgur.com/5aYYUOV.png) 無法輸入任何字母、數字進去,沒辦法改變這個 state 但是輸入了,什麼都沒有改變,因為 state 沒有變,還是 `''` 空字串 state 還是狀態不會變(immutable),要怎麼改變 state 呢? 可以在 `<input type='text '>` 裡面加入 `onChange` 的事件。 ``` + <input type='text' placeholder='new todo' value={value} onChange={handleInputChange}/> ``` :::info `onChange={handleInputChange}` `onCLick={handleButtonClick}` 命名慣例:handle 開頭。 ::: 那加上了 `onChange={handleInputChange}`,就要來實作功能: ```react= function App() { + function handleInputChange(e) { + console.log(e.target.value) + } return ( <div className="App"> + <input type='text' placeholder='new todo' value={value} onChange={handleInputChange} /> <button onClick={handleButtonClick}>Add todo</button> { todos.map(todo => <TodoItem content={todo} />) } </div> ) } export default App; ``` 每輸入一個字母,就會 `console.log(e.target.value)`,會把新輸入的 value 印出來 ![](https://i.imgur.com/lqBrZ3F.png) 現在要改成 `setValue` 改變 state 的值: ```react=2 function handleInputChange(e) { + setValue(e.target.value) } ``` ![](https://i.imgur.com/hjy3cO6.png) 今天輸入 a,觸發了 `handleInputCHange` 事件,此時`e.target.value` 為 a,所以 `value` 值為 a,只要 state 改變,就會 rerender,現在 `<input value={value} />` 的 `{value}` 變成 a。 今天我再來輸入 b,觸發 `handleInputCHange` 事件,此時`e.target.value` 為 ab,所以 `value` 值為 ab,只要 state 改變,就會 rerender,現在 `<input value={value} />` 的 `{value}` 變成 ab。 透過這個方式,就可以把 `input` 的 state 值,放入 state 內。 小結:放在 `controlled state` 裡面 #### 2. uncontrolled state 第二種是 uncontrolled state ---- ## React 官方教學 ![](https://i.imgur.com/4D37oKc.png) ### 什麼是 component?props? 其中前面提到:`{props.children}`,不太懂為什麼要使用 `props.children`。 所以從[Components 與 Props](https://zh-hant.reactjs.org/docs/components-and-props.html)介紹起: > ### Component 使你可以將 UI 拆分成獨立且可複用的程式碼,並且專注於各別程式碼的思考。本章節旨在介紹 component 的相關概念,你也可以在此參閱[詳細的 API 文件](https://zh-hant.reactjs.org/docs/react-component.html)。 > 概念上來說,component 就像是 JavaScript 的 function,它接收任意的參數(稱之為「props」)並且回傳描述畫面的 React element。 > from: [Components 與 Props](https://zh-hant.reactjs.org/docs/components-and-props.html) #### component 組件 就很像 CSS 切版的概念,將各小區塊的 UI寫在 JavaScript,還可以有著 JavaScript 的輔助,套用到程式的邏輯。 #### 如何建立一個 component? 建立一個 component 最簡單的方法就是 > 定義 component 最簡單的方法即是撰寫一個 Javascript function: ```javascript= function Welcome(props) { return <h1>Hello, {props.name}</h1>; } ``` > 此 function 是一個符合規範的 React component,因為它接受一個「props」(指屬性 properties)物件並回傳一個 React element。我們稱之為 function component,因為它本身就是一個 JavaScript function。 現在我們用一個 function 叫做 Welcome 輸入一個 React 參數 props,回傳一個 React element(`<h1> hello, {props.name}</h1>`)。 現在做好了一個 component,這樣就可以用程式的邏輯,將 UI 放在 JavaScript 上,我們會希望這個 `{props.name}` 如變數一般,可以替換。 回顧一下,先前我們要在 `ReactDOM.render()`插入 component 時,都是只有加入 component,沒輸入參數,所以使用的時候,就會如以下情形: ```javascript= ReactDOM.render( <Welcome />, // DOM 標籤的 React element document.querySelector() ) ``` 如果今天想要替換 Welcome component 裡面的變數的話,就可以這樣寫: `props` 是指`prperties` 屬性,這個用 function Welcome 符合 React component 的規則,也回傳了一個 `React element`(`<h1> hello, {props.name}</h1>`),其中 `properties` 為屬性。 ```javascript= // 建立一個 component function Welcome(props) { return <h1>Hello, {props.name}</h1>; } ``` > 當 React 看到由使用者定義 component 的 element 時,它將 JSX 屬性和 children 作為 single object 傳遞給該 component。我們稱這個 object 為「props」。 這邊自定義一個 `name` 的屬性(properties),我覺得應該是長相挺像 `HTML 標籤`,然後寫在標籤裡面的名稱,很像是自定義的屬性, ```javascript= const element = <Welcome name="Sara" />; // React element 也可以是使用者自定義的 component ``` 然後將 `React element` 放到 `ReactDOM.render()` 的 JSX 裡面: ```javascript= ReactDOM.render( element, document.getElementById('root') ); ``` > React 官方文件的說明: > 1. 我們對 `<Welcome name="Sara" />` 這個 element 呼叫了 ReactDOM.render()。 > 2. `React` 以 `{name: 'Sara'}` 作為 props 傳入 `Welcome component` 並呼叫。 > 3. `Welcome component` 回傳了 ``<h1>Hello, Sara</h1>`` 這個 element 作為返回值。 > 4. `React DOM` 有效的將 DOM 更新為 `<h1>Hello, Sara</h1>`。ˋ 現在知道怎麼使用跟建立自定義 `component`,然後先前說的 `React component` 的概念很像是把他分成很多個 UI 小區塊,再利用 JavaScript 程式的語法跟邏輯寫好 HTML、CSS 等等,現在切出了一塊小的 UI,但是如果這些小的 UI 組件,如果又像是 HTML 一樣,有幾個寫幾次的話,那就不符合有程式邏輯的寫法,所以現在要說明的就是以程式邏輯的寫法,寫 HTML 重複性的組件(component)。 ```javascript= function Welcome(props) { return <h1>Hello, {props.name}</h1>; } function App() { return ( <div> <Welcome name="Sara" /> <Welcome name="Cahal" /> <Welcome name="Edite" /> </div> ); } ReactDOM.render( <App />, document.getElementById('root') ); ``` :::info 1. component 命名慣例:大寫鴕峰 2. component 使用: (1) 建立:利用 function component or class component(ES6)定義跟建立一個 component (2) 使用:`<Welcome />`,如果有輸入參數的話就是像以上的範例:`<Welcome name='Sara' />`, (3) 使用方法有幾種: - 直接放到 `ReactDOM.render()` 的 JSX 裡面。 - 或者是再放到另一個 Component 內。 ::: ![](https://i.imgur.com/vjx5qGD.png) 上面提到了怎麼使用 Component 並 render 到頁面上,就像是上圖的 `TodoList` 只有一個 component。 不過前面提到其實 `component` 就像是 UI 一小塊一小塊的切版那樣,所以 `component` 裡面可能還會有 `component`,然後要靈活運用相似的區塊,讓裡面的 component 也要可以輸入參數改變值,所以下面需要學習怎麼讓 component 裡面還有 component 並可以傳入參數,就像是上圖的 todolist 在待辦清單的部分,有待辦事項、刪除按鈕、新增的輸入框等,由幾個小組件組成。 下面以[React 官方文件的範例為練習](https://zh-hant.reactjs.org/redirect-to-codepen/components-and-props/composing-components) ### 概念矯正 #### react element ```javascript= // 宣告一個 name 的變數,然後在 JSX 內使用 {} 來插入宣告的這個變數 name。 const name = 'Josh Perez'; // 這個 element 宣告 JSX 內容,後面要用在 JSX 處。 const element = <h1>Hello, {name}</h1>; // 錯誤寫法:const element = `<h1>Hello, {name}</h1>`; ReactDOM.render( element, document.getElementById('root') ); ``` > JSX 的大括號中寫入任何合法的 JavaScript expression。舉例來說,`2 + 2`、`user.firstName` 以及 `formatName(user)` > -- From:[React:介紹 JSX](https://zh-hant.reactjs.org/docs/introducing-jsx.html) 另外在[從 Hooks 開始,讓你的網頁 React 起來系列 第 5 篇](https://ithelp.ithome.com.tw/articles/10218644)也提到: > 我們也可以把 JSX 的內容抽成一個 JavaScript 變數,只需要把 JSX 的內容用小括號(`()`)包起來就好 但此時就在想,為什麼可以用 `()` 包起來呢?在[React 介紹 JSX]()中有提到: > 為了方便閱讀,我們將 JSX 拆成很多行表達。雖然這並不需要,我們建議將多行 JSX 包在括號中來避免遇到自動分號補足的麻煩。 舉例:在第 10 ~ 14 行,可以發現將 JSX 「**多行**」內容(JSX內容:`<h1>Hello, {formatName(user)}!</h1>`)以`()` 包起來,這樣**可以省去自動分號補足的麻煩** ```javascript= function formatName(user) { return user.firstName+ ' ' + user.lastName; } const user = { firstName: 'Harper', lastName: 'Perez' }; const element = ( <h1> Hello, {formatName(user)}! </h1> ); ReactDOM.render( element, document.getElementById('root') ); ``` 此外這個例子還示範了在 JSX 內容,可以`嵌入呼叫 JavaScript function (formatName(user)) 的回傳值` :::info 小結: 1. JSX 可以將 HTML 等等的內容抽出,以`()` 包覆,並令成變數,進階一步在 JSX 的內容裡,利用 `{}` 來插入一些 JavaScript 的變數(如:`<h1>Hello {name}</h1>`或者是 function裡回傳的值(如:`<h1>hello functionName(user))</h1>`。 ::: #### JSX 本身也是 expression 在經過編譯的 JSX expression 會變成 JavaScript 的 function,表示也可以使用 `if`、`for`中使用 JSX: ```react= function getGreeting(user) { if (user) { return <h1>Hello, {formatName(user)}!</h1>; } return <h1>Hello, Stranger.</h1>; } ``` #### 在 JSX 中指定屬性 可以在 JSX 指定 HTML tag 內的屬性(attribute),有兩種方法: 1. 如同 HTML attribute 一樣輸入「字串」 ```react= const element = <div tabIndex="0"></div>; ``` 2. 在屬性中使用大括號來嵌入一個 JavaScript expression ```react= const element = <img src={user.avatarUrl}></img>; ``` :::danger 不建議在 JSX 內的屬性混用 `{}` 及 `"string"`。 ::: :::warning > 注意: JSX 是寫在 JavaScript 內,所以要避開一些 JS 的語法像是 `class`(類別)就會和 HTML 的 CSS `class` 搞混,所以在此將 HTML CSS 的慣用的 `class` ,在 React 使用時,要改成 `className`,此外也將 HTML tag 的屬性(attribute)以小寫鴕峰表示,像是:`<div maxLength='10px'</div>` 中的 `maxLength` 改為小寫鴕峰。 ::: #### 在 JSX 中指定 Children 也可以在 JSX 內指定要哪些子 HTML tag 標籤,像是原本我們在 JavaScript 是: ```react= const element = ( <img src={user.avatarUrl} /> ) ``` 只有將一個 `<img>` 包成 JSX。 現在也可以在裡面指定子標籤: ``` const element = ( <div> <h1>Hello!</h1> <h2>Good to see you here.</h2> </div> ); ``` #### React element(JSX 表示物件) 參考:[JSX 介紹](https://zh-hant.reactjs.org/docs/introducing-jsx.html) 舉例: ```react= const element = ( <h1 className="greeting"> Hello, World! </h1> ); ``` 等同於以下: ```react= const element = React.createElement( 'h1', {className: 'greeting'}, 'Hello, World!' ); ``` 感覺使用 `React.createElement` 是將其拆解,然後[官方文件](https://zh-hant.reactjs.org/docs/introducing-jsx.html)上寫說會「會進行一些檢查以幫助你寫出沒有 bug 的程式」,會產生類似的物件(下面這個已經簡化過): ```react= const element = { type: 'h1', props: { className: 'greeting', children: 'Hello, world!' } }; ``` > 這種物件被稱呼為「React element」。你可以想像他們描述的是你想要在螢幕上看到的東西,React 會讀取這些物件並用這些描述來產生 DOM 並保持他們在最新狀態。 ### Render Element—— > React element 是單純的 object,而且很容易被建立。React DOM 負責更新 DOM 來符合 React element。 React element 是單純的 object,可以從前一篇章介紹 `JSX 表示物件——element` 複習起,然後在建立 React 應用程式的最小單位是「(React) element」。 ```react= // 要 render 一個 element 到 root DOM node ,就傳入 element 及 DOM node 兩者到 ReactDOM.render() const element = <h1>Hello, world</h1>; ReactDOM.render(element, document.getElementById('root')); ``` ### `React element` 是 `immutable`,那要怎麼更新? > React element 是 immutable 的。一旦你建立一個 element,你不能改變它的 children 或是 attribute。Element 就像是電影中的一個幀:它代表特定時間點的 UI。 憑藉我們迄今為止對 React 的認識,更新 UI 唯一的方式是建立一個新的 element,並且將它傳入到 ReactDOM.render()。 官網以 `setInterval` 在每秒來重新 render 當前時間。那這樣 `React element` 是 immutable,也不能總用 `setInterval` 來更新吧? 後面會提到一個 `stateful component` 的概念。 ## resources referenct [React Function Components](https://www.robinwieruch.de/react-function-component#react-function-component-props) ###### tags: `MTR05` `Lidemy 學習筆記`

    Import from clipboard

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lost their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template is not available.


    Upgrade

    All
    • All
    • Team
    No template found.

    Create custom template


    Upgrade

    Delete template

    Do you really want to delete this template?

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in via Google

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Tutorials

    Book Mode Tutorial

    Slide Mode Tutorial

    YAML Metadata

    Contacts

    Facebook

    Twitter

    Feedback

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions

    Versions and GitHub Sync

    Sign in to link this note to GitHub Learn more
    This note is not linked with GitHub Learn more
     
    Add badge Pull Push GitHub Link Settings
    Upgrade now

    Version named by    

    More Less
    • Edit
    • Delete

    Note content is identical to the latest version.
    Compare with
      Choose a version
      No search result
      Version not found

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub

        Please sign in to GitHub and install the HackMD app on your GitHub repo. Learn more

         Sign in to GitHub

        HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Available push count

        Upgrade

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Upgrade

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully