React如何使用localStorage及實(shí)現(xiàn)刪除筆記操作過(guò)程
1. 初始化notes
以下這段代碼完成了這些操作:
- 調(diào)用
localStorage.getItem("notes")從瀏覽器的本地存儲(chǔ)中獲取名為 “notes” 的數(shù)據(jù)。 - 使用
JSON.parse將獲取到的字符串解析成數(shù)組。 - 如果本地存儲(chǔ)中沒(méi)有 “notes” 數(shù)據(jù)(返回值為 null),則默認(rèn)將 notes 設(shè)置為空數(shù)組 []。
const [notes, setNotes] = React.useState(
JSON.parse(localStorage.getItem("notes")) || []
)useState鉤子
useState 是 React 的一個(gè)鉤子,用于在函數(shù)組件中引入狀態(tài)。
它返回一個(gè)數(shù)組,有兩個(gè)元素:
- 當(dāng)前狀態(tài)值(這里是 notes)。
- 更新?tīng)顟B(tài)的函數(shù)(這里是 setNotes)。
localStorage
localStorage是瀏覽器提供的 API,用于在本地存儲(chǔ)鍵值對(duì)數(shù)據(jù)。localStorage.getItem("notes")從localStorage中獲取鍵為 “notes” 的數(shù)據(jù),返回的結(jié)果是一個(gè)字符串。
JSON.parse
localStorage中存儲(chǔ)的所有數(shù)據(jù)都是字符串。JSON.parse將字符串解析為 JavaScript 對(duì)象。
如果存儲(chǔ)的數(shù)據(jù)是一個(gè) JSON 字符串,例如:“[1, 2, 3]”,調(diào)用 JSON.parse 后會(huì)得到 [1, 2, 3]。
|| 運(yùn)算符
- || 是邏輯或運(yùn)算符,用來(lái)提供一個(gè)默認(rèn)值。
- 如果
localStorage.getItem("notes")返回 null(即沒(méi)有找到 “notes” 鍵),JSON.parse(localStorage.getItem("notes"))的結(jié)果會(huì)是 null。 - 在這種情況下,表達(dá)式的右側(cè)([])會(huì)被返回,表示 notes 的初始值是一個(gè)空數(shù)組。
2. 每次notes發(fā)生改變時(shí),將notes保存到localStorage
React.useEffect(() => {
localStorage.setItem("notes", JSON.stringify(notes))
}, [notes])useEffect 是 React 的一個(gè)鉤子,用于在函數(shù)組件中處理副作用。
- 副作用通常指與組件渲染邏輯無(wú)關(guān)的行為,例如:數(shù)據(jù)獲取、訂閱、手動(dòng) DOM 操作、或者日志記錄等。
它的語(yǔ)法如下:
React.useEffect(effectFunction, dependencies);
effectFunction 是一個(gè)函數(shù),在特定條件下運(yùn)行。dependencies 是一個(gè)數(shù)組,控制 effectFunction 的運(yùn)行時(shí)機(jī)。
localStorage.setItem 是瀏覽器提供的 API,用于向 localStorage 中存儲(chǔ)鍵值對(duì)。
它接受兩個(gè)參數(shù):
- 鍵:存儲(chǔ)數(shù)據(jù)的名稱(chēng)(這里是 “notes”)。
- 值:存儲(chǔ)的具體數(shù)據(jù),必須是字符串。
JSON.stringify(notes):
- 將 notes 轉(zhuǎn)換為 JSON 格式的字符串,因?yàn)?
localStorage只能存儲(chǔ)字符串?dāng)?shù)據(jù)。
當(dāng)組件渲染后并且 notes 發(fā)生變化時(shí):
- useEffect 會(huì)被觸發(fā)。
- localStorage.setItem(“notes”, JSON.stringify(notes)) 將最新的 notes 數(shù)組保存到本地存儲(chǔ)中。
如果 notes 沒(méi)有變化:
- 即使組件重新渲染,useEffect 不會(huì)運(yùn)行,因?yàn)?notes 的值沒(méi)有改變。
3. 什么是 Lazy State Initialization?
通常情況下,useState 的初始值是直接計(jì)算出來(lái)的:
const [state, setState] = React.useState(computeInitialState());
- 這里
computeInitialState()會(huì)在組件每次渲染時(shí)立即執(zhí)行,即使結(jié)果只需要在初次渲染時(shí)使用。 - 如果
computeInitialState是一個(gè)復(fù)雜的計(jì)算函數(shù),就會(huì)浪費(fèi)性能。
為了解決這個(gè)問(wèn)題,React 提供了一種惰性初始化的方法:通過(guò)向 useState 傳遞一個(gè)函數(shù),而不是直接傳遞計(jì)算結(jié)果。這種函數(shù)只會(huì)在組件第一次渲染時(shí)執(zhí)行,之后不會(huì)再次調(diào)用。
惰性初始化
const [state, setState] = React.useState(() => computeInitialState());
- 當(dāng)傳遞一個(gè)函數(shù)給 useState 時(shí),React 只會(huì)在組件初次渲染時(shí)調(diào)用這個(gè)函數(shù)來(lái)計(jì)算初始狀態(tài)。
- 后續(xù)的狀態(tài)更新不再調(diào)用此函數(shù)。
4. 在React中實(shí)現(xiàn)刪除筆記的操作
<button
className="delete-btn"
onClick={(event) => props.deleteNote(event, note.id)}
>
<i className="gg-trash trash-icon"></i>
</button><button> 元素
- HTML 的按鈕標(biāo)簽,用于定義一個(gè)可點(diǎn)擊的交互元素。
- 在 React 中, 可以綁定事件和自定義屬性,并觸發(fā)相關(guān)的事件處理程序。
回調(diào)函數(shù)中的 (event) => props.deleteNote(event, note.id) 是一個(gè)箭頭函數(shù),執(zhí)行時(shí)調(diào)用 props.deleteNote 方法,并將兩個(gè)參數(shù)傳遞給它:
event:原生的點(diǎn)擊事件對(duì)象,提供有關(guān)點(diǎn)擊的信息(如目標(biāo)元素、鼠標(biāo)位置等)。note.id:當(dāng)前筆記的唯一標(biāo)識(shí)符,用于指定要?jiǎng)h除的具體筆記。
<i> 是 HTML 的行內(nèi)元素,通常用作圖標(biāo)的占位符。
function deleteNote(event, noteId){
event.stopPropagation()
setNotes(oldNotes => oldNotes.filter(note => note.id !== noteId))
}event.stopPropagation()
作用:
- 阻止事件從當(dāng)前元素傳播到父元素或其他祖先元素(即阻止事件冒泡)。
- 防止刪除按鈕的點(diǎn)擊事件觸發(fā)父組件的其他事件處理邏輯(如整個(gè)筆記項(xiàng)的點(diǎn)擊事件)。
場(chǎng)景舉例:
假設(shè)筆記項(xiàng)的外層組件有一個(gè)點(diǎn)擊事件綁定:
<div onClick={() => console.log("Note clicked!")}>
<button onClick={(event) => deleteNote(event, noteId)}>Delete</button>
</div>如果沒(méi)有 event.stopPropagation():
- 點(diǎn)擊刪除按鈕時(shí),既會(huì)觸發(fā)
deleteNote,又會(huì)觸發(fā)外層div的onClick。
有了 event.stopPropagation():
- 點(diǎn)擊刪除按鈕時(shí),只會(huì)觸發(fā)
deleteNote。
箭頭函數(shù) oldNotes => oldNotes.filter(...)setNotes 接收一個(gè)更新函數(shù),該函數(shù)的參數(shù)是當(dāng)前的狀態(tài)值 oldNotes。
filter 方法:
- 返回一個(gè)新數(shù)組,其中包含滿足條件的所有元素。
- 條件:保留 id 不等于 noteId 的筆記,即刪除 noteId 對(duì)應(yīng)的筆記。
完整邏輯
通過(guò) filter 遍歷 oldNotes 數(shù)組:
- 如果 note.id !== noteId,該筆記被保留。
- 如果 note.id === noteId,該筆記被過(guò)濾掉。
返回的新數(shù)組賦值給 notes,并觸發(fā)組件重新渲染。
5. 刪除按鈕的CSS實(shí)現(xiàn)
.delete-btn {
display: none;
background: none;
border: none;
}作用
- 定義刪除按鈕的初始樣式,默認(rèn)情況下按鈕是隱藏的。
屬性解釋
- display: none;:
隱藏元素,按鈕不占據(jù)布局空間,不可見(jiàn)。
- background: none;:
移除按鈕的默認(rèn)背景樣式。
- border: none;:
移除按鈕的默認(rèn)邊框。
.title:hover > .delete-btn {
display: block;
}作用
- 當(dāng)用戶(hù)將鼠標(biāo)懸停在 .title 元素上時(shí),其子元素 .delete-btn 顯示出來(lái)。
屬性解釋display: block;:
讓 .delete-btn 可見(jiàn),并以塊級(jí)元素形式顯示。
> .delete-btn:
- 表示只選擇直接子元素 .delete-btn,避免影響其他嵌套更深的 .delete-btn。
實(shí)現(xiàn)邏輯
通過(guò)偽類(lèi) :hover,動(dòng)態(tài)切換按鈕的顯示狀態(tài),提供更好的用戶(hù)交互體驗(yàn)。
.trash-icon {
cursor: pointer;
}作用
- 定義垃圾桶圖標(biāo)的樣式,使其在用戶(hù)鼠標(biāo)懸停時(shí)具有點(diǎn)擊效果。
屬性解釋cursor: pointer;:
鼠標(biāo)懸停時(shí)顯示手型指針,表示該元素可點(diǎn)擊。
.gg-trash {
box-sizing: border-box;
position: relative;
display: block;
transform: scale(var(--ggs,1));
width: 10px;
height: 12px;
border: 2px solid transparent;
box-shadow:
0 0 0 2px,
inset -2px 0 0,
inset 2px 0 0;
border-bottom-left-radius: 1px;
border-bottom-right-radius: 1px;
margin-top: 4px;
}作用
- 定義垃圾桶圖標(biāo)的外觀,包括大小、形狀和整體樣式。
屬性解釋box-sizing: border-box;:
- 控制元素的寬高計(jì)算方式,包含內(nèi)邊距和邊框。
position: relative;:
- 定義元素為相對(duì)定位,用于配合子元素的絕對(duì)定位。
transform: scale(var(--ggs,1));:
- 使用 CSS 變量 --ggs 控制縮放比例,默認(rèn)為 1。
width: 10px; height: 12px;:
- 定義垃圾桶的寬度和高度。
border: 2px solid transparent;:
設(shè)置透明的邊框。
box-shadow:
為垃圾桶形狀添加外邊框和內(nèi)部邊框:
- 0 0 0 2px:外部邊框,2px 寬。
- inset -2px 0 0 和 inset 2px 0 0:內(nèi)部分隔線。
border-bottom-left-radius 和 border-bottom-right-radius:
- 為垃圾桶底部的兩個(gè)角添加圓角。
margin-top: 4px;:
在頂部增加間距。
.gg-trash::after {
background: currentColor;
border-radius: 3px;
width: 16px;
height: 2px;
top: -4px;
left: -5px;
}作用
- 添加垃圾桶的橫梁部分(通常表示垃圾桶的蓋子)。
屬性解釋background: currentColor;:
使用當(dāng)前文本顏色作為背景顏色。
border-radius: 3px;:
添加圓角,使蓋子邊緣更平滑。
width: 16px; height: 2px;:
定義橫梁的大小。
top: -4px; left: -5px;:
使用絕對(duì)定位將橫梁放置在垃圾桶頂部的位置。
.gg-trash::before {
width: 10px;
height: 4px;
border: 2px solid;
border-bottom: transparent;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
top: -7px;
left: -2px;
}作用
- 添加垃圾桶的蓋子部分(彎曲的頂部結(jié)構(gòu))。
屬性解釋
width: 10px; height: 4px;:
- 定義蓋子的寬度和高度。
border: 2px solid;:
設(shè)置蓋子的邊框。
border-bottom: transparent;:
移除蓋子底部的邊框,使其開(kāi)口朝下。
border-top-left-radius 和 border-top-right-radius:
設(shè)置蓋子頂部的兩個(gè)角為圓角。
top: -7px; left: -2px;:
使用絕對(duì)定位將蓋子放置在垃圾桶頂部。
總結(jié):垃圾桶圖標(biāo)的整體實(shí)現(xiàn)
- .gg-trash 是垃圾桶的主體,包括邊框、陰影等基礎(chǔ)結(jié)構(gòu)。
- ::after 添加橫梁(垃圾桶蓋的下部分)。
- ::before 添加蓋子頂部的彎曲結(jié)構(gòu)。
結(jié)合這些樣式,實(shí)現(xiàn)了一個(gè)完整的垃圾桶圖標(biāo)。
交互效果總結(jié)
- .delete-btn 默認(rèn)隱藏,用戶(hù)鼠標(biāo)懸停在 .title 上時(shí)顯示。
- 鼠標(biāo)懸停時(shí),垃圾桶圖標(biāo)變?yōu)榭牲c(diǎn)擊狀態(tài),通過(guò)樣式 cursor: pointer 提供視覺(jué)提示。
6. 查找當(dāng)前筆記id
const [currentNoteId, setCurrentNoteId] = React.useState(
(notes[0]?.id) || ""
)
const currentNote = notes.find(note => note.id === currentNoteId) || notes[0]React.useState:
定義一個(gè)狀態(tài)變量 currentNoteId 和其對(duì)應(yīng)的更新函數(shù) setCurrentNoteId。
notes[0]?.id:
- 通過(guò)可選鏈操作符 (?.),嘗試訪問(wèn)數(shù)組
notes中第一項(xiàng)的 id。 - 如果 notes 數(shù)組為空或者
notes[0]為undefined,notes[0]?.id返回undefined而不會(huì)報(bào)錯(cuò)。
|| "":
如果 notes[0]?.id 為 undefined,currentNoteId 的初始值設(shè)置為空字符串 ""。
效果
如果 notes 數(shù)組非空,currentNoteId 的初始值是第一項(xiàng)筆記的 id。如果 notes 數(shù)組為空,currentNoteId 的初始值是 “”。
notes.find(note => note.id === currentNoteId):
- 使用
Array.prototype.find()方法在 notes 數(shù)組中查找 id 等于currentNoteId的筆記。 find方法返回第一個(gè)滿足條件的元素。如果沒(méi)有找到匹配的元素,返回undefined。
|| notes[0]:
如果沒(méi)有找到匹配的筆記(即 find 返回 undefined),使用 || 提供默認(rèn)值,返回 notes[0](數(shù)組的第一項(xiàng))。
到此這篇關(guān)于React自學(xué):如何使用localStorage,以及如何實(shí)現(xiàn)刪除筆記操作的文章就介紹到這了,更多相關(guān)React localStorage刪除筆記內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React實(shí)現(xiàn)點(diǎn)擊刪除列表中對(duì)應(yīng)項(xiàng)
本文主要介紹了React 點(diǎn)擊刪除列表中對(duì)應(yīng)項(xiàng)的方法。具有一定的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-01-01
詳解如何在React中監(jiān)聽(tīng)鼠標(biāo)事件
React可以通過(guò)使用React事件系統(tǒng)來(lái)監(jiān)聽(tīng)鼠標(biāo)事件,您可以在React組件中通過(guò)使用特定的事件處理函數(shù)來(lái)注冊(cè)和處理鼠標(biāo)事件,本文小編講給大家詳細(xì)介紹一下如何在React中監(jiān)聽(tīng)鼠標(biāo)事件,需要的朋友可以參考下2023-09-09
react組件中過(guò)渡動(dòng)畫(huà)的問(wèn)題解決
這篇文章主要為大家介紹了react組件中過(guò)渡動(dòng)畫(huà)的問(wèn)題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-09-09
在react中使用highlight.js將頁(yè)面上的代碼高亮的方法
本文通過(guò) highlight.js 庫(kù)實(shí)現(xiàn)對(duì)文章正文 HTML 中的代碼元素自動(dòng)添加語(yǔ)法高亮,具有一定的參考價(jià)值,感興趣的可以了解一下2022-01-01
React 組件轉(zhuǎn) Vue 組件的命令寫(xiě)法
本文先介紹兩個(gè)框架的組件共性和不兼容的地方,再介紹react-to-vue的使用和原理,需要的朋友可以參考下2018-02-02
React 中常用的幾種路由跳轉(zhuǎn)方式小結(jié)
基本路由跳轉(zhuǎn)是最常見(jiàn)的一種方式,下面介紹React 中常用的幾種路由跳轉(zhuǎn)方式,感興趣的朋友一起看看吧2023-12-12
基于react框架使用的一些細(xì)節(jié)要點(diǎn)的思考
下面小編就為大家?guī)?lái)一篇基于react框架使用的一些細(xì)節(jié)要點(diǎn)的思考。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05

