背景:React現在已經更新到19了,文檔地址也做了全面的更新,上一次系統性的學習還是在16-17的大版本更新。所以,現在就開始重新學習吧~
學習內容:
- React官網教程:https://zh-hans.react.dev/learn/describing-the-ui
- 其他輔助資料(看到再補充)
補充說明:這次學習更多的是以學習筆記的形式記錄,看到哪記到哪
1. 基礎知識
React 應用是由被稱為 組件 的獨立 UI 片段構建而成。React 組件本質上是可以任意添加標簽的 JavaScript 函數
React 允許你將標簽、CSS 和 JavaScript 組合成自定義“組件”,即 應用程序中可復用的 UI 元素
React 組件是一段可以使用標簽進行擴展 的 JavaScript 函數,組件的名稱必須以大寫字母開頭(React的語法規定,這樣它才能分清是React組件還是正常的html標簽)
// export default 導出聲明
// function Profile 定義函數,function名必須首字母大寫export default function Profile() {
// return 如果換行,就必須用()將內容包裹
// 沒有括號包裹的話,任何在 return 下一行的代碼都將被忽略!return (<imgsrc="https://i.imgur.com/MK3eW3Am.jpg"alt="Katherine Johnson"/>)// 或者 標簽只有一行的時候括號可以省略return <img src="https://i.imgur.com/MK3eW3Am.jpg" alt="Katherine Johnson" />)
}// 你可以只定義組件一次,然后按需多處和多次使用
export default function Gallery() {return (<section><h1>了不起的科學家</h1><Profile /><Profile /><Profile /></section>);
}// 組件不建議嵌套組件定義,不然會很慢并且可能會有bug產生
export default function Gallery() {// 🔴 永遠不要在組件中定義組件function Profile() {// ...}// ...
}// 使用時可以import './Gallery.js' 或者 './Gallery',在 React 里都能正常使用,只是前者更符合 原生 ES 模塊
import Gallery from './Gallery';
import Gallery from './Gallery.js';
導出方式
默認導出 vs 具名導出
一個文件里有且僅有一個 默認 導出,但是可以有任意多個 具名 導出
當使用默認導入時,可以在 import 語句后面進行任意命名。比如 import Banana from ‘./Button.js’。相反,對于具名導入,導入和導出的名字必須一致。
同一文件中,有且僅有一個默認導出,但可以有多個具名導出
語法 | 導出語句 | 導入語句 |
---|---|---|
默認 | export default function Button() {} | import Button from ‘./Button.js’; |
具名 | export function Button() {} | import { Button } from ‘./Button.js’; |
JSX
- 只能返回一個根元素
在一個組件中包含多個元素,需要用一個父標簽把它們包裹起來,如果不想添加新的dom元素,可以使用<>...</>(Fragment)
,React Fragment 允許將子元素分組,而不會在 HTML 結構中添加額外節點
原因:JSX 雖然看起來很像 HTML,但在底層其實被轉化為了 JavaScript 對象,你不能在一個函數中返回多個對象,除非用一個數組把他們包裝起來 - 標簽必須閉合
這是強制規定,要么自閉合(<img />
),要么添加閉合標簽(<li>...</li>
) - 使用駝峰式命名法給大部分屬性命名
JSX 最終會被轉化為 JavaScript,而 JSX 中的屬性也會變成 JavaScript 對象中的鍵值對。組件經常會遇到需要用變量的方式讀取這些屬性的時候。但 JavaScript 對變量的命名有限制,所以需要避開這些限制- 變量名稱不能包含 - 符號,所以屬性大部分用駝峰
- 變量不能用保留字如class,所以在jsx中用className代替
- 由于歷史原因,aria-* 和 data-* 屬性是以帶 - 符號的 HTML 格式書寫的
需要將一個字符串屬性傳遞給 JSX 時,把它放到單引號或雙引號
// "" 引號中的內容按照字符串的形式處理,單引號雙引號都可以,但使用雙引號會多點
// {} 大括號中的內容會被動態引用,直接在標簽中使用 JavaScript,可以在其他地方聲明,在使用的時候直接讀取js對應的值
// 大括號內的任何 JavaScript 表達式都能正常運行
export default function Avatar() {
const alt = "Gregorio Y. Zara"
//return (<imgclassName="avatar"src="https://i.imgur.com/7vQD0fPs.jpg"alt={alt}/>);
}
大括號使用場景:
- 用作 JSX 標簽內的文本:
<h1>{name}'s To Do List</h1>
是有效的,但是<{tag}>Gregorio Y. Zara's To Do List</{tag}>
無效。 - 用作緊跟在 = 符號后的 屬性:
src={avatar}
會讀取 avatar 變量,但是src="{avatar}"
只會傳一個字符串 {avatar}
在JSX中還可以傳遞對象,對象也是用大括號表示,所以要引用對象的時候就需要使用兩個括號
JSX 是一種模板語言的最小實現,因為它允許你通過 JavaScript 來組織數據和邏輯
Props
React 組件使用 props 來互相通信。每個父組件都可以提供 props 給它的子組件,從而將一些信息傳遞給它,包括對象、數組和函數等
import { getImageUrl } from './utils.js';
// props是組件的唯一參數
// function里使用大括號獲取props是解構
// 也可以寫成這樣
// function Avatar(props) {
// const person = props.person
// const size = props.size
// }
// 如果你想在沒有指定值的情況下給 prop 一個默認值,可以通過在參數后面寫 = 和默認值來進行解構
// 默認值僅在缺少 size prop 或 size={undefined} 時生效,等于null都不行
function Avatar({ person, size=100 }) {
// person 和 size 是可訪問的return (<imgclassName="avatar"src={getImageUrl(person)}alt={person.name}width={size}height={size}/>);
}export default function Profile() {
// 這樣使用不同的參數,就能展示出兩個類似但是又獨立的組件,這就是組件復用一個很重要的意義return (<div><Avatarsize={100}person={{ name: 'Katsuko Saruhashi', imageId: 'YfeOqp2'}}/><Avatarsize={80}person={{name: 'Aklilu Lemma', imageId: 'OKS67lh'}}/></div>);
}// 還可以使用 JSX 展開語法傳遞 props
// 像這個場景,props里面所有的內容都是需要傳遞到Avatar組件中時,就可以直接用展開語法傳遞
function Profile({ person, size, isSepia, thickBorder }) {return (<div className="card"><Avatarperson={person}size={size}isSepia={isSepia}thickBorder={thickBorder}/></div>);
}
// 可以寫成這樣
function Profile(props) {return (<div className="card"><Avatar {...props} /></div>);
}
// 假設Profile 中isSepia不需要傳遞,其他都需要,還可以寫成這樣
function Profile({isSepia, ...rest}) {return (<div className="card"><Avatar {...rest} /></div>);
}
當你將內容嵌套在 JSX 標簽中時,父組件將在名為 children 的 prop 中接收到該內容
通俗的來說就是某個組件標簽內容,在接收的時候會自動處理成children的props
<Aaa><div>里面是一系列的內容</div> </Aaa>
,在聲明Aaa這個組件時,有一個隱藏props,children,表示的就是div及其包裹的內容
可以將帶有 children prop 的組件看作有一個“洞”,可以由其父組件使用任意 JSX 來“填充”
import Avatar from './Avatar.js';function Card({ children }) {return (<div className="card">{children}</div>);
}export default function Profile() {return (<Card><Avatarsize={100}person={{ name: 'Katsuko Saruhashi',imageId: 'YfeOqp2'}}/></Card>);
}
props 是 不可變的。當一個組件需要改變它的 props(例如,響應用戶交互或新數據)時,它不得不“請求”它的父組件傳遞 不同的 props —— 一個新對象!它的舊 props 將被丟棄,最終 JavaScript 引擎將回收它們占用的內存
Props 是只讀的時間快照:每次渲染都會收到新版本的 props
你不能改變 props。當你需要交互性時,你可以設置 state。
渲染
在 React 中,你可以通過使用 JavaScript 的 if 語句、&& 和 ? : 運算符來選擇性地渲染 JSX