React 練習 - 便條紙

閱讀時間約 9 分鐘

最近正在學 React,看見課程中要做出一個類似便條紙的頁面,老師說靈感來自 Google Keep,紀錄自己的想法後丟上去。

google keep頁面

google keep頁面

課程裡做出來的:

post-it 頁面

post-it 頁面


主要是練習 React 中的 props 跟怎麼使用狀態,以下是寫出來的 component 之間的關係。

<App>
<Header />
<CreateNote />
<Note />
<Footer />
<App />

使用 useState 將表單元素轉成可控制元件

首先是新增便條紙 <CreateNote /> 的部分,要將不可控的元素轉成可控制元素(controlled elements),因為表單元素是由 DOM 管理輸入的狀態,​轉成受控元素就能允許 React 保持對輸入的控制。

步驟:

  • 使用 useState 來初始化狀態
const [note, setNote] = useState({ title: '', content: '' })
  • 建立處理事件的函數
function handleChange(e) {
const { name, value } = e.target
setNote((note) => {
return { ...note, [name]: value }
})
}
  • 將狀態綁定與函數在元素
<input
// ...
onChange={handleChange}
value={note.title}/>
<textarea
// ...
onChange={handleChange}
value={note.content}/>

這時候元素的輸入值就可以預測(因為是我們在控制的),也能進行動態更新。

提升狀態到父元件 Lift states up

使用者在新增便條紙後,接收值的元件是 <Note /> ,它不是 <CreateNote /> 的子元件。

由於 React 中資料只能由上往下流動,當父元件或其他兄弟元件需要使用同個狀態時,必須將狀態提升到上一層的公共父元件,在這裡就是 <App />

步驟:

  • 提升狀態到 App 元件
const [notes, setNotes] = useState([])

function handleAddNote(newNote) {
setNotes((notes) => [...prevNotes, newNote])
}

function handleDeleteNote(id) {
setNotes((notes) => notes.filter((note, i) => i !== id))
}
  • 用 props 傳遞給 CreateNoteNote 元件
<CreateNote onAddNote={handleAddNote} />
注意 notes 是陣列 要用 map 迭代資料給 Note
{notes.map((note, i) => {
return (
<Note
key={i}
id={i}
title={note.title}
content={note.content}
onDeleteNote={handleDeleteNote}/>
)
})}
  • 使用 props
function CreateNote({ onAddNote }) {
// ...
function handleClick(e) {
e.preventDefault()
onAddNote(note)
}
return (
// ...
<button onClick={handleClick}>Add</button>
)
}
function Note({ id, title, content, onDeleteNote }) {
return (
<div className="note">
<h2>{title}</h2>
<p>{content}</p>
<button onClick={() => onDeleteNote(id)}>DELETE</button>
</div>
)
}

現在新增便條紙後,發現就算沒有寫任何內容還是可以新增,所以回到 CreateNote 加上一個預防動作:

function handleClick(e) {
e.preventDefault()
// 新增以下這行
if (note.title === '' || note.content === '') return
// 當沒有內容時 就不再執行​
onAddNote(note)
}

使用 useEffect 將資料存在 localStorage

新增完便條紙後,如果重新整理網頁,狀態就會回到初始狀態,也就是空的陣列:

const [notes, setNotes] = useState([]) // 初始狀態為空陣列

於是就想到可以把資料存在 localStorage,讓使用者下次打開頁面時,可以再將儲存的資料渲染出來。

步驟:

  • 將上面那段改寫
const [notes, setNotes] = useState(function () {
const storageValue = localStorage.getItem('notes')
return storageValue ? JSON.parse(storageValue) : []
// 如果 localStorage 沒有資料 返回空陣列
})
  • 新增 useEffect
useEffect(
function () {
localStorage.setItem('notes', JSON.stringify(notes))
},
[notes]
// 當 notes 更新時 執行上面的函數
)

完成!

為了提高重用度 改寫成 Custom Hook

很多時候,將資料儲存到 localStorage 是常有的事,如果可以把上面那一大段程式碼寫成自定義的 Hook,未來其他專案要使用時,也能輕鬆移植過去。

最後就是要來寫 Custom Hook:

  • 程式碼寫在另一個檔案 使用 use 命名 Custom Hook
export function useLocalStorageState(initialValue, key) {}
  • 將剛剛寫的 useState、useEffect 剪下貼過來
export function useLocalStorageState(initialValue, key) {
const [value, setValue] = useState(function () {
const storageValue = localStorage.getItem(key)
return storageValue ? JSON.parse(storageValue) : initialValue
})

useEffect(
function () {
localStorage.setItem(key, JSON.stringify(value))
},
[value, key]
)
}
  • 返回陣列或物件
export function useLocalStorageState(initialValue, key) {
const [value, setValue] = useState(function () {
const storageValue = localStorage.getItem(key)
return storageValue ? JSON.parse(storageValue) : initialValue
})

useEffect(
function () {
localStorage.setItem(key, JSON.stringify(value))
},
[value, key]
)

return [value, setValue] // 返回陣列
}
  • 在元件中導入 Custom Hook
const [notes, setNotes] = useLocalStorageState([], 'notes')

這樣就大功告成啦!

重新整理也不會遺失寫好的便條紙

重新整理也不會遺失寫好的便條紙



練習 repo 頁面 ▶ Post-it - build with React

avatar-img
5會員
14內容數
本來是理科生,在被物理放棄之後成為了文科生,有時理性思考,偶爾卻會脫口出感性的字句;喜歡打字的聲音,以生活為靈感寫下過去、現在與未來。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
碎碎念 的其他內容
C2 開始終於使用到 visual studio code, 這個階段學到 JavaScript 核心概念、DOM 操作、API 串接、MVC 架構, 每天都在 coding,每週都在追進度, 用壓縮到極致的時間寫完作業, 但跟著課程內容寫程式碼,真的有學到嗎? 有,吧。 畢竟在寫最後的電影清單
這次的 Frontend Mentor challenge 是新手村最後一個挑戰 ▶ Intro component with sign up form 網頁,使用 jQuery validation plugin。
開始接觸網頁開發後,發現自己缺乏實作經驗, 於是老師推了 Frontend Mentor challenge , 免費的通常是獨立頁面,花錢則是可以挑戰多頁式網站, 初學還沒學到 javascript 或 API 也沒關係, 新手也有提供 HTML/CSS 的練習。 很適合用來增加自己寫網頁的經驗,
理解問題,然後拆解,最後解決它。 通常網頁開發的課程流是 HTML - CSS - JavaScript , 但在 AC 一開始就先淺談 JavaScript , 就是要先建立運算思維:
孔子說三十而立,我卻三十而迷失了自己, 這個世界給得價值觀太過沈重, 原本不在意的,在褪去青春之後,都成為了後悔的來源; 後悔沒有選OO系、沒有攻讀研究所、沒有超前部署自己的人生, 最後遺失了勇氣,想要往前邁進得步伐依舊跨不出舒適圈, 於是季節繼續更迭、身邊的夥伴來來去去, 好像只有我被自己困住了。
C2 開始終於使用到 visual studio code, 這個階段學到 JavaScript 核心概念、DOM 操作、API 串接、MVC 架構, 每天都在 coding,每週都在追進度, 用壓縮到極致的時間寫完作業, 但跟著課程內容寫程式碼,真的有學到嗎? 有,吧。 畢竟在寫最後的電影清單
這次的 Frontend Mentor challenge 是新手村最後一個挑戰 ▶ Intro component with sign up form 網頁,使用 jQuery validation plugin。
開始接觸網頁開發後,發現自己缺乏實作經驗, 於是老師推了 Frontend Mentor challenge , 免費的通常是獨立頁面,花錢則是可以挑戰多頁式網站, 初學還沒學到 javascript 或 API 也沒關係, 新手也有提供 HTML/CSS 的練習。 很適合用來增加自己寫網頁的經驗,
理解問題,然後拆解,最後解決它。 通常網頁開發的課程流是 HTML - CSS - JavaScript , 但在 AC 一開始就先淺談 JavaScript , 就是要先建立運算思維:
孔子說三十而立,我卻三十而迷失了自己, 這個世界給得價值觀太過沈重, 原本不在意的,在褪去青春之後,都成為了後悔的來源; 後悔沒有選OO系、沒有攻讀研究所、沒有超前部署自己的人生, 最後遺失了勇氣,想要往前邁進得步伐依舊跨不出舒適圈, 於是季節繼續更迭、身邊的夥伴來來去去, 好像只有我被自己困住了。
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
11/20日NVDA即將公布最新一期的財報, 今天Sell Side的分析師, 開始調高目標價, 市場的股價也開始反應, 未來一週NVDA將重新回到美股市場的焦點, 今天我們要分析NVDA Sell Side怎麼看待這次NVDA的財報預測, 以及實際上Buy Side的倉位及操作, 從
Thumbnail
Hi 大家好,我是Ethan😊 相近大家都知道保濕是皮膚保養中最基本,也是最重要的一步。無論是在畫室裡長時間對著畫布,還是在旅途中面對各種氣候變化,保持皮膚的水分平衡對我來說至關重要。保濕化妝水不僅能迅速為皮膚補水,還能提升後續保養品的吸收效率。 曾經,我的保養程序簡單到只包括清潔和隨意上乳液
Thumbnail
React 表單驗證是一種技術與使用者體驗的設計,讓使用者能夠即時檢查輸入的資料並修正,提升使用者的使用體驗,並確保資料的正確性。
Thumbnail
React Hook onclick call a callback function with params, and change css style example: 本筆記參考: 1. https://www.codegrepper.com/code-examples/javascrip
Thumbnail
接續上一篇,navbar元件其實寫的不是很好,還不能說是可真正reuse,我們把程式改成這樣,透過props傳入navbar的items,定義好navbar title, li的href/name/active等等,就可以達到navbar元件無須改code就能重用的目的! Navbar 元件中用m
Thumbnail
接續上一篇,這邊要來寫一個React hello world app,最後安裝webpack-dev-server來提升開發效率。 使用npm安裝react, react-dom: $ npm install react react-dom --save dependencies下紀錄的是生產環境會
Thumbnail
React開發有兩種方式,一種是使用CDN方式include react的官方lib,然後使用babel來將JSX編譯成瀏覽器看得懂的javascript。 但是在react中還會使用到sass, scss等等,還需要額外編譯成css瀏覽器才看得懂。 而webpack的誕生,就是為了解決上述的問題,
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
11/20日NVDA即將公布最新一期的財報, 今天Sell Side的分析師, 開始調高目標價, 市場的股價也開始反應, 未來一週NVDA將重新回到美股市場的焦點, 今天我們要分析NVDA Sell Side怎麼看待這次NVDA的財報預測, 以及實際上Buy Side的倉位及操作, 從
Thumbnail
Hi 大家好,我是Ethan😊 相近大家都知道保濕是皮膚保養中最基本,也是最重要的一步。無論是在畫室裡長時間對著畫布,還是在旅途中面對各種氣候變化,保持皮膚的水分平衡對我來說至關重要。保濕化妝水不僅能迅速為皮膚補水,還能提升後續保養品的吸收效率。 曾經,我的保養程序簡單到只包括清潔和隨意上乳液
Thumbnail
React 表單驗證是一種技術與使用者體驗的設計,讓使用者能夠即時檢查輸入的資料並修正,提升使用者的使用體驗,並確保資料的正確性。
Thumbnail
React Hook onclick call a callback function with params, and change css style example: 本筆記參考: 1. https://www.codegrepper.com/code-examples/javascrip
Thumbnail
接續上一篇,navbar元件其實寫的不是很好,還不能說是可真正reuse,我們把程式改成這樣,透過props傳入navbar的items,定義好navbar title, li的href/name/active等等,就可以達到navbar元件無須改code就能重用的目的! Navbar 元件中用m
Thumbnail
接續上一篇,這邊要來寫一個React hello world app,最後安裝webpack-dev-server來提升開發效率。 使用npm安裝react, react-dom: $ npm install react react-dom --save dependencies下紀錄的是生產環境會
Thumbnail
React開發有兩種方式,一種是使用CDN方式include react的官方lib,然後使用babel來將JSX編譯成瀏覽器看得懂的javascript。 但是在react中還會使用到sass, scss等等,還需要額外編譯成css瀏覽器才看得懂。 而webpack的誕生,就是為了解決上述的問題,