編寫(xiě)干凈高效的React代碼 - 最佳實(shí)踐和優(yōu)化技術(shù)
讓我們深入了解如何編寫(xiě)干凈、高效的 React 代碼,這些代碼不僅運(yùn)行良好,而且更易于理解、維護(hù)和擴(kuò)展。
(更|多優(yōu)質(zhì)內(nèi)|容:java567 點(diǎn) c0m)
1. 實(shí)現(xiàn)錯(cuò)誤邊界以?xún)?yōu)雅地處理組件錯(cuò)誤
使用錯(cuò)誤邊界包裝您的組件或應(yīng)用程序的特定部分,以便以受控方式捕獲和處理錯(cuò)誤。
這可以防止整個(gè)應(yīng)用程序崩潰并提供回退 UI 或錯(cuò)誤消息,從而改善用戶(hù)體驗(yàn)并更輕松地調(diào)試問(wèn)題。
高階組件 (HOC) - withErrorBoundary:
?// HOC for error boundary
?const withErrorBoundary = (WrappedComponent) => {
? ?return (props) => {
? ? ?const [hasError, setHasError] = useState(false);
? ? ?const [errorInfo, setErrorInfo] = useState(null);
?
? ? ?useEffect(() => {
? ? ? ?const handleComponentError = (error, errorInfo) => {
? ? ? ? ?setHasError(true);
? ? ? ? ?setErrorInfo(errorInfo);
? ? ? ? ?// You can also log the error to an error reporting service here
? ? ? ?};
?
? ? ? ?window.addEventListener('error', handleComponentError);
?
? ? ? ?return () => {
? ? ? ? ?window.removeEventListener('error', handleComponentError);
? ? ? ?};
? ? ?}, []);
?
? ? ?if (hasError) {
? ? ? ?// You can customize the fallback UI or error message here
? ? ? ?return <div>Something went wrong. Please try again later.</div>;
? ? ?}
?
? ? ?return <WrappedComponent {...props} />;
? ?};
?};
用法:
?// HOC for error boundary
?import withErrorBoundary from './withErrorBoundary';
?
?const Todo = () => {
? ?// Component logic and rendering
?}
?
?const WrappedComponent = withErrorBoundary(Todo);
2.使用React.memo作為功能組件
React.memo 是一個(gè)高階組件,可以記住功能組件的結(jié)果,防止不必要的重新渲染。
通過(guò)使用 React.memo 包裝功能組件,您可以在組件的 props 未更改時(shí)跳過(guò)重新渲染來(lái)優(yōu)化性能。
這是一個(gè)例子,
?// ?
?const TodoItem = ({text}) => {
? ?return <div> {text} </div>
?}
?
?// Todo
?
?const Todo = () => {
? //... Component logic
?
?return <div>
? //.. Other elements
? ? <TodoItem //.. />
?</div>
?}
在此示例中,我們有一個(gè)名為 TodoItem 的功能組件,它接收 name 屬性并呈現(xiàn) todo 文本。
默認(rèn)情況下,只要Todo 父組件重新渲染,該組件就會(huì)重新渲染。
為了優(yōu)化性能,我們可以用 React.memo 包裝TodoItem,創(chuàng)建該組件的記憶版本。這個(gè)記憶組件只有在它的 props 發(fā)生改變時(shí)才會(huì)重新渲染。
?// ? Memoized version of TodoItem using React.memo
?const TodoItem = React.memo(({text}) => {
? ?return <div> {text} </div>
?})
通過(guò)使用React.memo,我們可以防止不必要的重新渲染并優(yōu)化功能組件的性能。
然而,值得注意的是,React.memo 執(zhí)行props 的淺層比較。如果您的組件接收復(fù)雜的數(shù)據(jù)結(jié)構(gòu)作為 props,請(qǐng)確保正確處理 prop 更新以實(shí)現(xiàn)準(zhǔn)確的記憶。
3. 使用 Linting 來(lái)提高代碼質(zhì)量
使用 linter 工具(例如 ESLint)可以極大地提高 React 項(xiàng)目中的代碼質(zhì)量和一致性。
通過(guò)使用 linter,您可以:
確保代碼風(fēng)格一致
捕獲錯(cuò)誤和有問(wèn)題的模式
提高代碼的可讀性和可維護(hù)性
執(zhí)行編碼標(biāo)準(zhǔn)和約定
4.避免默認(rèn)導(dǎo)出
默認(rèn)導(dǎo)出的問(wèn)題在于,它可能會(huì)導(dǎo)致更難理解哪些組件正在被導(dǎo)入并在其他文件中使用。它還限制了導(dǎo)入的靈活性,因?yàn)槟J(rèn)導(dǎo)出每個(gè)文件只能有一個(gè)默認(rèn)導(dǎo)出。
?// ? Avoid default export
?const Todo = () => {
? ?// component logic...
?};
?
?export default Todo; ?
相反,建議在 React 中使用命名導(dǎo)出:
?// ? Use named export
?const Todo = () => {
?
?}
?
?export { Todo };
使用命名導(dǎo)出可以在導(dǎo)入組件時(shí)提供更好的清晰度,使代碼庫(kù)更有組織性并且更易于導(dǎo)航。
命名導(dǎo)入與tree shake配合得很好。
Tree Shaking 是 JavaScript 上下文中常用的一個(gè)術(shù)語(yǔ),用于描述死代碼的刪除。它依賴(lài)于導(dǎo)入和導(dǎo)出語(yǔ)句來(lái)檢測(cè)是否導(dǎo)出和導(dǎo)入代碼模塊以在 JavaScript 文件之間使用。
重構(gòu)變得更加容易。
更容易識(shí)別和理解模塊的依賴(lài)關(guān)系。
5.使用對(duì)象解構(gòu)
當(dāng)我們使用點(diǎn)符號(hào)直接屬性訪問(wèn)來(lái)訪問(wèn)對(duì)象的各個(gè)屬性時(shí),對(duì)于簡(jiǎn)單的情況來(lái)說(shuō)效果很好。
?// ? Avoid direct property access using dot notation
?const todo = {
? ? id: 1,
? ? name: "Morning Task",
? ? completed: false
?}
?
?const id = todo.id;
?const name = todo.name;
?const completed = todo.completed;
這種方法對(duì)于簡(jiǎn)單的情況可以很好地工作,但是當(dāng)處理較大的對(duì)象或僅需要屬性的子集時(shí),它可能會(huì)變得困難且重復(fù)。
另一方面,對(duì)象解構(gòu)提供了一種更簡(jiǎn)潔、更優(yōu)雅的方式來(lái)提取對(duì)象屬性。它允許您在一行代碼中解構(gòu)一個(gè)對(duì)象,并使用類(lèi)似于對(duì)象文字表示法的語(yǔ)法將多個(gè)屬性分配給變量。
?// ? Use object destructuring
?const { id, name = "Task", completed } = todo;
它減少了重復(fù)訪問(wèn)對(duì)象屬性的需要。
支持默認(rèn)值的分配。
允許變量重命名和別名。
6.使用片段
片段通過(guò)在渲染多個(gè)元素時(shí)避免不必要的包裝 div 來(lái)實(shí)現(xiàn)更清晰的代碼。
?// ? Avoid unnecessary wrapper div
?const Todo = () => (
? ?<div>
? ? ?<h1>Title</h1>
? ? ?<ul>
? ? ? ?// ...
? ? ?</ul>
? ?</div>
?);
在上面的代碼中,不必要的包裝 div 會(huì)給 DOM 結(jié)構(gòu)增加不必要的復(fù)雜性,可能會(huì)影響網(wǎng)頁(yè)的可訪問(wèn)性。
?// ? Use fragments
?const Todo = () => (
? ?<>
? ? ?<h1>Title</h1>
? ? ?<ul>
? ? ? ?// ...
? ? ?</ul>
? ?</>
?);
7. 更喜歡傳遞對(duì)象而不是多個(gè) props
當(dāng)我們使用多個(gè)參數(shù)或 props 將用戶(hù)相關(guān)信息傳遞給組件或函數(shù)時(shí),記住每個(gè)參數(shù)的順序和用途可能會(huì)很困難,尤其是當(dāng)參數(shù)數(shù)量增加時(shí)。
?// ? Avoid passing multiple arguments
?const updateTodo = (id, name, completed) => {
? //...
?}
?
?// ? Avoid passing multiple props
?const TodoItem = (id, name, completed) => {
? ?return(
? ? ?//...
? ?)
?}
當(dāng)參數(shù)數(shù)量增加時(shí),維護(hù)和重構(gòu)代碼變得更具挑戰(zhàn)性。犯錯(cuò)誤的可能性會(huì)增加,例如省略參數(shù)或提供不正確的值。
?// ? Use object arguments
?const updateTodo = (todo) => {
? //...
?}
?
?const todo = {
? ? id: 1,
? ? name: "Morning Task",
? ? completed: false
?}
?
?updateTodo(todo);
函數(shù)變得更加自我描述并且更容易理解。
減少因參數(shù)順序不正確而導(dǎo)致錯(cuò)誤的機(jī)會(huì)。
無(wú)需更改函數(shù)簽名即可輕松添加或修改屬性。
簡(jiǎn)化調(diào)試或測(cè)試函數(shù)以將對(duì)象作為參數(shù)傳遞的過(guò)程。
8.使用箭頭功能
箭頭函數(shù)提供了更簡(jiǎn)潔的語(yǔ)法和詞法作用域,消除了顯式綁定的需要this并提高了代碼可讀性。
?// ?
?function sum(a, b) {
? ?return a + b;
?}
上面的代碼可能會(huì)導(dǎo)致冗長(zhǎng)的代碼,并可能導(dǎo)致對(duì) . 的上下文和綁定的誤解this。
?// ? Use arrow function
?const sum = (a, b) => a + b;
箭頭函數(shù)使代碼更加緊湊和富有表現(xiàn)力。
它自動(dòng)綁定上下文,減少相關(guān)錯(cuò)誤的機(jī)會(huì)this。
它提高了代碼的可維護(hù)性。
9. 使用枚舉代替數(shù)字或字符串
?// ? Avoid Using numbers or strings
?switch(status) {
? ?case 1:
? ? ?return //...
? ?case 2:
? ? ?return //...
? ?case 3:
? ? ?return //...
?}
上面的代碼更難理解和維護(hù),因?yàn)閿?shù)字的含義可能不會(huì)立即清晰。
?// ? Use Enums
?const Status = {
? ?NOT_STARTED: 1,
? ?IN_PROGRESS: 2,
? ?COMPLETED: 3
?}
?
?const { NOT_STARTED, IN_PROGRESS COMPLETED } = Status;
?
?switch(status) {
? ?case NOT_STARTED:
? ? ?return //...
? ?case IN_PROGRESS:
? ? ?return //...
? ?case COMPLETED:
? ? ?return //...
?}
枚舉具有有意義且自我描述的值。
提高代碼可讀性。
減少拼寫(xiě)錯(cuò)誤或錯(cuò)誤值的可能性。
更好的類(lèi)型檢查、編輯器自動(dòng)完成和文檔。
10. 使用布爾屬性的簡(jiǎn)寫(xiě)
?// ?
?<Dropdown multiSelect={true} />
?// ? Use shorthand
?<Dropdown multiSelect />
布爾屬性的簡(jiǎn)寫(xiě)語(yǔ)法通過(guò)減少不必要的冗長(zhǎng)并使意圖清晰來(lái)提高代碼的可讀性。
11.避免使用索引作為關(guān)鍵道具
?// ? Avoid index as key
?const renderItem = (todo, index) => {
? ?const {name} = todo;
? ?return <li key={index}> {name} </>
?}
使用索引作為關(guān)鍵屬性可能會(huì)導(dǎo)致不正確的渲染尤其是在添加、刪除或重新排序列表項(xiàng)時(shí)。
它可能會(huì)導(dǎo)致性能不佳和組件更新不正確。
?// ? Using unique and stable identifiers
?const renderItem = (todo, index) => {
? ?const {id, name} = todo;
? ?return <li key={id}> {name} </>
?}
有效地更新和重新排序列表中的組件。
減少潛在的渲染問(wèn)題。
避免不正確的組件更新。
12. 在小函數(shù)中使用隱式返回
?// ? Avoid using explicit returns
?const square = value => {
? ?return value * value;
?}
當(dāng)我們使用顯式返回時(shí),可能會(huì)使小函數(shù)定義變得不必要地更長(zhǎng)且更難以閱讀。
由于附加的花括號(hào)和顯式的 return 語(yǔ)句,可能會(huì)導(dǎo)致代碼更加混亂。
?// ? Use implicit return
?const square = value => value * value;
隱式返回減少了代碼的冗長(zhǎng)。
提高代碼可讀性。
它可以通過(guò)關(guān)注主要邏輯而不是返回語(yǔ)句來(lái)增強(qiáng)代碼的可維護(hù)性。
13.使用PropTypes進(jìn)行類(lèi)型檢查
?// ? Bad Code
?const Button = ({ text, enabled }) =>
? ? ? ?<button enabled>{text}</button>;
上面的代碼可能會(huì)導(dǎo)致傳遞不正確的prop 類(lèi)型,這可能會(huì)導(dǎo)致運(yùn)行時(shí)錯(cuò)誤或意外行為。
?// ? Use PropTypes
?import PropTypes from 'prop-types';
?
?const Button = ({ enabled, text }) =>
? ? ? ?<button enabled> {text} </button>;
?
?Button.propTypes = {
? ?enabled: PropTypes.bool
? ?text: PropTypes.string.isRequired,
?};
它有助于捕獲編譯時(shí)的錯(cuò)誤。
它提供了更好的理解和組件的預(yù)期類(lèi)型。
PropTypes 充當(dāng)使用該組件的其他開(kāi)發(fā)人員的文檔。
14. 更喜歡使用模板文字
?// ? Bad Code
?const title = (seriesName) =>
? ? ? ?"Welcome to " + seriesName + "!";
上面的代碼可能會(huì)導(dǎo)致冗長(zhǎng)的代碼,并使字符串插值或連接變得更加困難。
?// ? Use template literals
?const title = (seriesName) =>
? ? ? ?`Welcome to ${seriesName}!`;
它通過(guò)允許在字符串內(nèi)進(jìn)行變量插值來(lái)簡(jiǎn)化字符串操作。
它使代碼更具表現(xiàn)力并且更易于閱讀。
它支持多行字符串,無(wú)需額外的解決方法。
改進(jìn)代碼格式。
15.避免使用巨大的組件
避免在 React 中使用大型組件對(duì)于維護(hù)干凈、模塊化和可維護(hù)的代碼至關(guān)重要。
大型組件往往更復(fù)雜、更難理解并且容易出現(xiàn)問(wèn)題。讓我們通過(guò)一個(gè)例子來(lái)說(shuō)明這個(gè)概念:
?// ? Avoid huge component
?const Todo = () => {
? ?// State Management
? ?const [text, setText] = useState("");
? ?const [todos, setTodos] = useState([])
? ?//... More states
?
? ?// Event Handlers
? ?const onChangeInput = () => //...
? ?// Other event handlers
?
? ?return (
? ? <div>
? ? ? ?<input //.. />
? ? ? ?<input //.. /> ?
? ? ? ?<button //.. />
? ? ? ?<list //... >
? ? ? ? ?<list-item //..>
? ? ? ?</list/>
? ? </div>
? ?)
?};
?
?export default Todo; ?
在上面的示例中,我們有一個(gè)名為 的組件Todo,其中包含多個(gè)狀態(tài)變量以及事件處理程序和元素。
隨著組件的增長(zhǎng),管理、調(diào)試和理解變得更加困難。
請(qǐng)繼續(xù)關(guān)注即將推出的專(zhuān)門(mén)討論React 優(yōu)化技術(shù)的博客。我們將探索其他策略來(lái)提高組件的性能和效率。不要錯(cuò)過(guò)這些寶貴的見(jiàn)解!
快樂(lè)編碼!????????????