React自學 基礎一

React基礎

React 是一個由 Facebook(現 Meta)開發并維護的、開源JavaScript 庫,主要用于 構建用戶界面(UI),尤其是單頁面應用程序中的動態、交互式界面。

image-20250612192645692

簡單示例:

import React, { useState } from 'react';function Counter() {const [count, setCount] = useState(0); // 使用 React Hooks 管理狀態return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);
}

一、創建React工程

創建 React 項目主要有三種主流方式,根據你的需求(如開發效率、性能要求、是否需要服務端渲染等),可靈活選擇以下任一方法:


🚀 一、使用 Vite(推薦:速度快、現代化)

Vite 是當前最受歡迎的 React 項目初始化工具,啟動速度和熱更新遠超傳統工具,適合絕大多數新項目。
操作步驟:

  1. 確保已安裝 Node.js(建議 v16+)。

  2. 在終端執行以下命令:

    npm create vite@latest my-vite-app -- --template react
    
  3. 進入項目目錄并安裝依賴:

    cd my-vite-app
    npm install
    
  4. 啟動開發服務器:

    npm run dev
    
    • 訪問 http://localhost:5173 查看項目。
  5. 在Chrome瀏覽器中添加組件

    React 因其高效、靈活和強大的社區支持,成為現代前端開發的主流選擇之一。

    在Chrome瀏覽器中添加組件

    image-20250628204026748

    image-20250628204129958


?? 二、使用 Next.js(適合服務端渲染/靜態站點)

若項目需服務端渲染(SSR)、靜態生成(SSG)或強 SEO 支持(如博客、電商),Next.js 是最佳選擇。
操作步驟:

  1. 創建項目:
    npx create-next-app@latest my-next-app
    
  2. 進入目錄并啟動:
    cd my-next-app
    npm run dev
    
    • 訪問 http://localhost:3000

🧩 三、使用 create-react-app(傳統方式,已逐漸淘汰)

雖然官方仍在維護,但啟動慢、配置隱藏,僅適合學習或兼容舊項目。
操作步驟:

  1. 全局安裝(可選):
    npm install -g create-react-app
    
  2. 創建項目:
    npx create-react-app my-app
    
  3. 啟動項目:
    cd my-app
    npm start
    
    • 訪問 http://localhost:3000

📊 三種方式對比與適用場景

工具優勢適用場景啟動命令
Vite? 超快啟動、輕量、配置靈活新項目、開發效率優先npm run dev
Next.js🌐 服務端渲染、SEO 友好、全棧能力博客、電商、需 SEO 的應用npm run dev
CRA🧠 零配置、官方維護(但慢)學習 React 基礎npm start

? 常見問題解答(FAQ)

  • Q1:是否需要全局安裝工具?
    不需要!現代工具(如 Vite、Next.js)通過 npx 直接運行最新版本,避免全局依賴沖突。
  • Q2:項目名稱能否用大寫字母?
    不能!所有工具均要求項目名全小寫(如 my-app)。
  • Q3:如何修改默認端口?
    package.json 的啟動命令后添加 --port=新端口號,例如:
    npm run dev -- --port=4000
    

💎 總結建議

  • 新手/一般項目 → 選 Vite,體驗流暢開發;
  • 內容型網站/SEO 關鍵 → 選 Next.js,直接支持服務端渲染;
  • 學習 React 基礎 → 可嘗試 create-react-app,但注意其性能局限。

提示:以上命令均需在終端(如 VS Code 終端、命令行)執行。遇到依賴問題可嘗試 npm install --force 強制重裝。

image-20250612193145686

image-20250612193431658

image-20250630173947566

二、JSX

2.1 關于 JSX

JSX(JavaScript XML) 是一種 JavaScript 的語法擴展(解析工具進行特定解析),由 Facebook 團隊為 React 框架設計。它的核心作用是將 HTML 結構直接嵌入 JavaScript 代碼中,實現聲明式的 UI 構建。

核心特點:
  1. 類 HTML 語法
    允許在 JavaScript 中編寫類似 HTML 的標簽(例如 <div>Hello</div>)。

  2. JavaScript 表達式嵌入
    { } 包裹動態內容(如變量、函數調用):

    const name = "Alice";
    const element = <h1>Hello, {name}</h1>; // 動態渲染
    
  3. 編譯為 JavaScript
    JSX 本身不能被瀏覽器直接執行,需要通過工具(如 Babel)編譯為標準 JavaScript:

    // 編譯前 (JSX)
    <button className="btn">Click</button>// 編譯后 (JavaScript)
    React.createElement("button", { className: "btn" }, "Click");
    
  4. 與 React 深度集成
    主要用于構建 React 組件的 UI 結構,但也可用于其他庫(如 Vue 的 JSX 支持)。


2.2 關于 Babel (https://babeljs.io/)

Babel 是一個 JavaScript 編譯器,它的核心功能是將新版本的 JavaScript 代碼(或 JSX 等擴展語法)轉換為向后兼容的舊版本 JavaScript,確保代碼能在所有瀏覽器中運行。

關鍵作用:
  1. 編譯 JSX
    將 JSX 語法轉換為瀏覽器可理解的 React.createElement() 調用(如上例所示)。
  2. 轉譯現代 JavaScript
    將 ES6+ 代碼(如箭頭函數、async/await、類)轉換為 ES5 等舊標準。
    // 編譯前 (ES6)
    const list = items.map(item => <li key={item.id}>{item.name}</li>);// 編譯后 (ES5)
    var list = items.map(function(item) {return React.createElement("li", { key: item.id }, item.name);
    });
    
  3. 插件化架構
    通過插件支持實驗性語法(如裝飾器)、類型檢查(TypeScript)、代碼優化等。

2.3 JSX 與 Babel 的關系

  1. 依賴 Babel 處理
    JSX 必須通過 Babel(或類似工具)編譯為純 JavaScript 才能運行。
  2. 常用預設
    在 React 項目中,通常使用 Babel 預設插件 @babel/preset-react 來編譯 JSX。
  3. 工作流程示例
    JSX 代碼
    Babel 編譯
    標準 JavaScript
    瀏覽器執行

2.4 如何使用?

  1. 安裝 Babel
    npm install @babel/core @babel/preset-react
    
  2. 配置 Babel(創建 .babelrc 文件):
    {"presets": ["@babel/preset-react"]
    }
    
  3. 與構建工具集成
    配合 Webpack/Rollup 等工具自動完成編譯(例如使用 babel-loader)。

? 總結

  • JSX 是描述 UI 的語法糖,需編譯為 JavaScript。
  • Babel 是編譯工具鏈的核心,處理 JSX 和現代 JavaScript 的兼容性問題。
    官網 babeljs.io 提供了實時編譯演示、插件文檔和配置指南。

二(支線)、JSX 中使用 JavaScript 表達式

在 JSX 中,你可以使用大括號 {} 來嵌入 JavaScript 表達式。這允許你在 JSX 中動態地插入值、執行計算和渲染邏輯。

2.1 基本用法

const name = 'John Doe';
const element = <h1>Hello, {name}</h1>;

image-20250701154930359

2.2 表達式類型

  1. 變量引用

    const user = { firstName: 'Jane', lastName: 'Doe' };
    const element = <p>{user.firstName} {user.lastName}</p>;
    
  2. 函數調用

   function formatName(user) {return `${user.firstName} ${user.lastName}`;}const element = <h2>{formatName(user)}</h2>;
  1. 算術運算
   const total = 10;const count = 3;const element = <p>Remaining: {total - count}</p>;
  1. 三元表達式

    const isLoggedIn = true;
    const element = (<div>{isLoggedIn ? 'Welcome back!' : 'Please sign in'}</div>
    );
  2. 數組方法(列表渲染)

 const numbers = [1, 2, 3, 4, 5];const listItems = numbers.map((number) => <li key={number}>{number}</li>);

2.3 JSX 中的列表渲染示例

列表渲染是 React 中常見的操作,通常使用 map() 方法來遍歷數組并生成一組 JSX 元素。下面提供多個不同場景的列表渲染示例:

2.3.1 基礎列表渲染
const fruits = ['Apple', 'Banana', 'Orange'];function FruitList() {return (<ul>{fruits.map((fruit, index) => (<li key={index}>{fruit}</li>))}</ul>);
}
2.3.2 對象數組渲染
const users = [{ id: 1, name: 'Alice', age: 25 },{ id: 2, name: 'Bob', age: 30 },{ id: 3, name: 'Charlie', age: 35 }
];function UserTable() {return (<table><thead><tr><th>Name</th><th>Age</th></tr></thead><tbody>{users.map(user => (<tr key={user.id}><td>{user.name}</td><td>{user.age}</td></tr>))}</tbody></table>);
}
2.3.3 帶條件的列表渲染

在 JSX 中,我們經常需要根據條件來決定是否渲染某些內容。JavaScript 的邏輯與 (&&) 運算符和三元運算符 (?:) 是兩種常用的條件渲染方式。

1. 邏輯與 (&&) 運算符
{condition && <Component />}

condition 為真時,渲染 <Component />;否則不渲染任何內容。

示例
function Greeting({ isLoggedIn }) {return (<div>{isLoggedIn && <h1>Welcome back!</h1>}</div>);
}// 使用
<Greeting isLoggedIn={true} />  // 顯示 "Welcome back!"
<Greeting isLoggedIn={false} /> // 不顯示任何內容
特點
  • 簡潔,適合簡單的條件渲染
  • 當條件為 false 時,React 會跳過渲染(不會渲染 nullfalse
  • 注意:如果 condition0 這樣的 falsy 值,會渲染 0 而不是跳過
2. 三元運算符 (?:)
{condition ? <ComponentA /> : <ComponentB />}

condition 為真時,渲染 <ComponentA />;否則渲染 <ComponentB />

示例
function Greeting({ isLoggedIn }) {return (<div>{isLoggedIn ? (<h1>Welcome back!</h1>) : (<h1>Please sign in.</h1>)}</div>);
}// 使用
<Greeting isLoggedIn={true} />  // 顯示 "Welcome back!"
<Greeting isLoggedIn={false} /> // 顯示 "Please sign in."
特點
  • 適合需要兩種不同渲染結果的場景
  • 更明確地表達兩種可能性
  • 可以嵌套使用(但不推薦過于復雜的嵌套)
3. 在 JSX 外部使用 if 語句
提前決定要渲染的內容
function Greeting({ isLoggedIn }) {let content;if (isLoggedIn) {content = <h1>Welcome back!</h1>;} else {content = <h1>Please sign in.</h1>;}return <div>{content}</div>;
}
function renderContent(isLoggedIn) {if (isLoggedIn) {return <h1>Welcome back!</h1>;}return <h1>Please sign in.</h1>;
}function Greeting({ isLoggedIn }) {return <div>{renderContent(isLoggedIn)}</div>;
}
4. 立即執行函數來包含 if 邏輯
function Greeting({ isLoggedIn }) {return (<div>{(() => {if (isLoggedIn) {return <h1>Welcome back!</h1>;} else {return <h1>Please sign in.</h1>;}})()}</div>);
}
5.使用 switch 語句
function StatusIndicator({ status }) {let indicator;switch (status) {case 'loading':indicator = <Spinner />;break;case 'success':indicator = <Checkmark />;break;case 'error':indicator = <ErrorIcon />;break;default:indicator = null;}return <div>{indicator}</div>;
}
6.比較
方法適用場景優點缺點
外部 if復雜條件邏輯清晰易讀需要額外變量
IIFE簡單內聯條件保持內聯語法稍復雜
提取函數可復用的條件渲染可復用,易于測試需要跳轉查看邏輯
switch多個互斥條件結構清晰代碼量較多
&& 運算符單一條件,渲染或不渲染簡潔只能處理單一條件
三元運算符二選一渲染表達式形式,內聯嵌套時難以閱讀
最佳實踐建議
處理 false 值的注意事項
// 當 count 為 0 時,&& 會渲染 0
{count && <Message count={count} />}// 修復方法:明確布爾值轉換
{count > 0 && <Message count={count} />}
{!!count && <Message count={count} />}
  1. 簡單條件:使用 && 更簡潔
  2. 二選一渲染:使用三元運算符
  3. 避免復雜嵌套:如果條件太復雜,考慮提取為函數或組件
  4. 保持可讀性:復雜的條件邏輯可以拆分成多個變量

選擇哪種方式主要取決于具體場景和個人/團隊的編碼風格偏好,重要的是保持代碼的一致性和可讀性。

const products = [{ id: 1, name: 'Laptop', inStock: true },{ id: 2, name: 'Phone', inStock: false },{ id: 3, name: 'Tablet', inStock: true }
];function ProductList() {return (<ul>{products.map(product => (product.inStock && (<li key={product.id}>{product.name} - {product.inStock ? 'In Stock' : 'Out of Stock'}</li>)))}</ul>);
}
2.3.4 嵌套列表渲染
const departments = [{id: 1,name: 'Development',employees: ['John', 'Jane', 'Mike']},{id: 2,name: 'Design',employees: ['Sarah', 'Tom']}
];function DepartmentList() {return (<div>{departments.map(dept => (<div key={dept.id}><h3>{dept.name}</h3><ul>{dept.employees.map((employee, index) => (<li key={index}>{employee}</li>))}</ul></div>))}</div>);
}
2.3.5 使用組件渲染列表項
function TodoItem({ todo }) {return (<li><input type="checkbox" checked={todo.completed} /><span>{todo.text}</span></li>);
}function TodoList() {const todos = [{ id: 1, text: 'Learn React', completed: true },{ id: 2, text: 'Build a project', completed: false },{ id: 3, text: 'Deploy to production', completed: false }];return (<ul>{todos.map(todo => (<TodoItem key={todo.id} todo={todo} />))}</ul>);
}
2.3.6 重要注意事項
  1. key 屬性:列表中的每個元素都應該有一個唯一的 key 屬性,通常使用數據中的 ID,

    // 好
    {items.map(item => <li key={item.id}>{item.name}</li>)}// 如果沒有 ID,可以使用索引(但不推薦用于動態列表)
    {items.map((item, index) => <li key={index}>{item.name}</li>)}
    
  2. 避免在渲染時修改數據:不要在 map 內部修改原始數組

  3. 性能優化:對于大型列表,考慮使用虛擬滾動技術(如 react-window 庫)

2.4 注意事項

  • JSX 中的表達式必須是返回值的表達式,不能使用語句(如 if 語句)
  • 對于條件渲染,可以使用三元運算符或邏輯與 (&&) 運算符
  • 對象不能直接作為子元素渲染,需要轉換為字符串或提取特定屬性
// 錯誤示例
const user = { name: 'John' };
const element = <div>{user}</div>; // 錯誤// 正確示例
const element = <div>{user.name}</div>; // 正確
const element = <div>{JSON.stringify(user)}</div>; // 正確

JSX 中的 JavaScript 表達式使得動態 UI 的創建變得簡單而強大。

image-20250701154101729

三、事件綁定+組件

3.1 React事件綁定

在 JSX 中綁定 React 事件與在 HTML 中綁定 DOM 事件類似,但有一些關鍵區別。以下是 React 事件綁定的主要特點和使用方法:

3.1.1 基本語法
<button onClick={handleClick}>點擊我
</button>
(1)與 HTML 事件的區別
  1. 命名采用駝峰式onclickonClickonchangeonChange
  2. 傳入函數而不是字符串onclick="handleClick()"onClick={handleClick}
  3. 默認行為阻止方式不同:不能通過返回 false 來阻止默認行為
(2)常見事件類型
  • onClick - 點擊事件
  • onChange - 表單元素變化
  • onSubmit - 表單提交
  • onMouseEnter - 鼠標進入
  • onMouseLeave - 鼠標離開
  • onKeyDown - 鍵盤按下
  • onFocus - 獲取焦點
  • onBlur - 失去焦點
3.1.2【1】事件處理函數
function handleClick(event) {// event 是合成事件(SyntheticEvent)console.log('按鈕被點擊了', event);
}function App() {return <button onClick={handleClick}>點擊</button>;
}

3.1.2 【2】 傳遞參數
(1)如果需要傳遞額外參數給事件處理函數
function handleClick(id, event) {console.log('ID:', id, '事件:', event);
}function App() {return (<button onClick={(e) => handleClick(123, e)}>帶參數點擊</button>);
}

image-20250701175635340

🔍 特點分析:
  • 事件對象正確傳遞onClick={(e) => handleClick(123, e)} 中的 e 是 React 事件對象,被顯式傳遞給了 handleClick 函數。
  • 函數簽名匹配handleClick(id, event) 的兩個參數(idevent)都得到了正確的值。
  • 用途場景:當需要訪問事件對象(如阻止默認行為、獲取事件目標等)時,這種方式是推薦的。
(2)箭頭函數的

不能直接寫函數調用,這事件綁定需要一個函數引用

function handleClick(event) {console.log('事件:', event);
}const App = () => {return (<button onClick={() => handleClick(123)}>帶參數點擊</button>);
};

image-20250701175624204

🔍 問題分析:
  • 事件對象未傳遞onClick={() => handleClick(123)} 中的 handleClick 僅接收 123 作為參數,事件對象(event)沒有被傳入
  • 函數簽名不匹配handleClick(event) 期望的是一個 event 參數,但實際傳入的是 123,因此 event 參數會是 undefined
  • 潛在錯誤:如果 handleClick 中依賴 event 的值(如 event.target.valueevent.preventDefault() 等),會導致運行時錯誤或行為異常。
3.1.3 類組件中的綁定

在類組件中,通常需要在構造函數中綁定 this 或使用箭頭函數:

class MyComponent extends React.Component {constructor(props) {super(props);this.handleClick = this.handleClick.bind(this);}handleClick() {console.log('this:', this);}// 或者使用箭頭函數自動綁定 thishandleClick = () => {console.log('this:', this);}render() {return <button onClick={this.handleClick}>點擊</button>;}
}
3.1.4阻止默認行為和事件冒泡
function handleClick(event) {event.preventDefault(); // 阻止默認行為event.stopPropagation(); // 阻止事件冒泡console.log('事件處理');
}
3.1.5 合成事件(SyntheticEvent)

React 的事件是合成事件,是對原生事件的跨瀏覽器包裝,具有與原生事件相同的接口,包括:

  • event.preventDefault()
  • event.stopPropagation()
  • event.target
  • event.currentTarget
3.1.6 注意事項
  1. 事件處理函數中的 this 默認不是組件實例,需要手動綁定
  2. 避免在 render 方法中創建新函數,可能導致不必要的重新渲染
  3. React 17+ 中事件委托不再附加到 document,而是附加到 React 渲染的根 DOM 容器

正確的事件綁定方式可以幫助你編寫更高效、更易維護的 React 組件。

3.2 React組件

3.2.1 基礎使用

React 組件是構建用戶界面的獨立、可復用的代碼單元,將 UI 拆分為獨立模塊。每個組件管理自身的狀態和邏輯,通過組合形成復雜界面。

image-20250703132838717

/*原生寫法*/
function Button (){return <button>Button</button>
}/*或者使用箭頭函數的寫法*/
const Button = () =>{return <button>Button</button>
}

使用上

/*自閉和*/
<Button/>
/*成對標簽*/
<Button/><Button/>
3.2.2 基礎樣式控制

在 React 中,控制組件樣式有多種基礎方式,每種方式各有適用場景。以下是主要方法及代碼示例:

1. 內聯樣式 (Inline Styles)

直接在 JSX 元素中使用 style 屬性,傳入樣式對象(屬性名需駝峰命名

function Button() {return (<button style={{padding: "10px 20px",backgroundColor: "blue",color: "white",borderRadius: "4px",cursor: "pointer"}}>點擊我</button>);
}

特點

  • ? 簡單直接,適合動態樣式
  • ? 無法使用偽類(:hover)和媒體查詢
  • ? 性能不如 CSS 類(大量使用可能影響渲染)

2. 外部 CSS 文件

傳統 CSS 引入方式(最常用)

/* Button.css */
.my-button {padding: 10px 20px;background-color: blue;color: white;border-radius: 4px;cursor: pointer;
}.my-button:hover {background-color: darkblue; /* 支持偽類 */
}

組件中引入:

import "./Button.css";function Button() {return <button className="my-button">點擊我</button>;
}

特點

  • ? 支持所有 CSS 特性
  • ? 瀏覽器緩存優化
  • ? 全局作用域(需注意類名沖突)

3. CSS Modules(推薦)

自動局部作用域(文件命名:[name].module.css

/* Button.module.css */
.button {padding: 10px 20px;background: blue;
}

組件中使用:

import styles from "./Button.module.css";function Button() {return <button className={styles.button}>點擊我</button>;
}

編譯后類名會變成唯一值(如 Button_button__1H2k5

特點

  • ? 避免類名沖突
  • ? 支持所有 CSS 特性
  • ? 與普通 CSS 寫法一致

4. CSS-in-JS 庫 (如 styled-components)

通過 JavaScript 編寫樣式(需安裝庫)

npm install styled-components
import styled from "styled-components";// 創建帶樣式的組件
const StyledButton = styled.button`padding: 10px 20px;background: ${props => props.primary ? "blue" : "gray"};color: white;border-radius: 4px;&:hover {background: darkblue; /* 支持偽類 */}
`;function App() {return (<><StyledButton>普通按鈕</StyledButton><StyledButton primary>主要按鈕</StyledButton></>);
}

特點

  • ? 動態樣式支持最佳
  • ? 自動處理作用域
  • ? 增加包體積
  • ? 學習曲線較陡

5. 實用類庫 (Tailwind CSS)

原子化 CSS 方案(需配置)

function Button() {return (<button className="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">點擊我</button>);
}

特點

  • ? 快速原型開發
  • ? 響應式設計便捷
  • ? 需學習類名系統
  • ? HTML 可能臃腫

選擇建議:
場景推薦方式
簡單原型/少量動態樣式內聯樣式
傳統項目/團隊熟悉 CSS外部 CSS + BEM
組件化/避免類名沖突CSS Modules
復雜動態樣式/主題系統CSS-in-JS
快速開發/統一設計系統Tailwind CSS

最佳實踐提示

  1. 大型項目推薦 CSS ModulesCSS-in-JS
  2. 避免過度使用內聯樣式(性能考慮)
  3. 動態樣式可結合:className 條件拼接 或 CSS 變量
  4. 使用 :where() 降低 CSS 特異性(如 :where(.card) .title

四、useState

useState 是 React 中用于聲明組件狀態的一個 Hook,它讓函數組件能夠擁有自己的內部狀態。(向組件添加一個狀態變量,一旦變化UI也隨之變化**(數據驅動視圖**))

通過 useState,你可以在組件內部保存數據并在數據發生變化時重新渲染組件。

image-20250703133721750

4.1 useState 基礎結構

const [state, setState] = useState(initialValue);
  • state:當前狀態值(只讀)
  • setState:更新狀態的函數
  • initialValue:狀態的初始值(可以是任何類型)
React原則
🔒 狀態是只讀的
📖 狀態讀取
🚫 不可直接修改
🔄 狀態更新
🆕 必須創建新值替換
? 狀態替換
📥 狀態初始化

4.2 狀態不可變性原則詳解

4.2.1 為什么狀態必須不可變?
  1. 變更檢測:React 通過引用比較檢測狀態變化
  2. 性能優化:避免不必要的重新渲染
  3. 可預測性:狀態變更路徑清晰可追蹤
  4. 時間旅行調試:支持狀態歷史記錄和回滾
4.2.2 錯誤 vs 正確更新方式對比

必須創建狀態的新副本進行替換,而不是直接修改現有狀態。

狀態類型錯誤方式(直接修改)正確方式(創建新值)
對象user.age = 31;
setUser(user);
setUser({...user, age: 31});
數組items.push('new');
setItems(items);
setItems([...items, 'new']);
嵌套對象user.address.city = 'Paris';setUser({...user, address: {...user.address, city: 'Paris'}});

image-20250703145808001

4.3 待處理:狀態管理實戰模式

1. 表單狀態處理
function UserForm() {const [user, setUser] = useState({name: '',email: '',preferences: { theme: 'light', notifications: true }});const handleChange = (field, value) => {setUser(prev => ({...prev,[field]: value}));};const toggleTheme = () => {setUser(prev => ({...prev,preferences: {...prev.preferences,theme: prev.preferences.theme === 'light' ? 'dark' : 'light'}}));};return (<form><input value={user.name} onChange={e => handleChange('name', e.target.value)} /><input value={user.email} onChange={e => handleChange('email', e.target.value)} /><button type="button" onClick={toggleTheme}>切換主題(當前:{user.preferences.theme}</button></form>);
}

image-20250703144751042

2. 列表狀態管理
function TodoList() {const [todos, setTodos] = useState([{ id: 1, text: '學習React', completed: false }]);// 添加新任務(創建新數組)const addTodo = text => {setTodos(prev => [...prev,{ id: Date.now(), text, completed: false }]);};// 切換任務狀態(創建新對象)const toggleTodo = id => {setTodos(prev => prev.map(todo => todo.id === id ? { ...todo, completed: !todo.completed } : todo));};// 刪除任務(創建過濾后的新數組)const deleteTodo = id => {setTodos(prev => prev.filter(todo => todo.id !== id));};return (<div><ul>{todos.map(todo => (<li key={todo.id}><input type="checkbox"checked={todo.completed}onChange={() => toggleTodo(todo.id)}/><span style={{ textDecoration: todo.completed ? 'line-through' : 'none' }}>{todo.text}</span><button onClick={() => deleteTodo(todo.id)}>刪除</button></li>))}</ul></div>);
}

4.4 待處理:高級技巧與優化策略

1. 函數式更新
// 當新狀態依賴舊狀態時使用
setCount(prevCount => prevCount + 1);// 批量更新示例
const incrementTwice = () => {setCount(prev => prev + 1); // 使用前值計算setCount(prev => prev + 1); // 確保兩次更新都生效
};
2. 惰性初始化
// 復雜初始狀態的計算只執行一次
const [data, setData] = useState(() => {const expensiveValue = calculateExpensiveValue();return expensiveValue;
});
3. 狀態結構優化
復雜狀態
拆分為多個useState
使用useReducer
使用Immer庫
提高可讀性
集中狀態邏輯
簡化不可變更新
4. 使用 Immer 簡化不可變更新
import produce from 'immer';const [user, setUser] = useState({name: 'Alice',profile: {level: 5,achievements: ['新手', '探索者']}
});// 使用 Immer 進行"可變式"更新(底層仍不可變)
const addAchievement = title => {setUser(produce(draft => {draft.profile.achievements.push(title);}));
};const updateLevel = () => {setUser(produce(draft => {draft.profile.level += 1;}));
};

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/912945.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/912945.shtml
英文地址,請注明出處:http://en.pswp.cn/news/912945.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

PHP語法基礎篇(八):超全局變量

超全局變量是在 PHP 4.1.0 中引入的&#xff0c;并且是內置變量&#xff0c;可以在所有作用域中始終可用。 PHP 中的許多預定義變量都是"超全局的"&#xff0c;這意味著它們在一個腳本的全部作用域中都可用。在函數或方法中無需執行 global $variable; 就可以訪問它們…

NumPy-核心函數concatenate()深度解析

NumPy-核心函數concatenate深度解析 一、concatenate()基礎語法與核心參數函數簽名與核心作用基礎特性&#xff1a;形狀匹配規則 二、多維數組拼接實戰示例1. 一維數組&#xff1a;最簡單的序列拼接2. 二維數組&#xff1a;按行與按列拼接對比按行拼接&#xff08;垂直方向&…

aws(學習筆記第四十八課) appsync-graphql-dynamodb

aws(學習筆記第四十八課) appsync-graphql-dynamodb 使用graphql來方便操作dynamodb 理解graphql中的graphql api&#xff0c;schema&#xff0c;resolver 學習內容&#xff1a; graphqlgraphql apischemaresolver 1. 代碼連接和修改 1.1 代碼鏈接 代碼鏈接&#xff08;app…

關于微前端框架micro,子應用設置--el-primary-color失效的問題

設置了manualChunks導致失效,去掉即可,比較小眾的問題 下面是deepseek的分析 關于 manualChunks 導致 Element Plus 主題變量失效的問題 你找到的確實是問題的關鍵所在。這個 manualChunks 配置影響了 Element Plus 樣式和變量的加載順序&#xff0c;從而導致主題變量失效。…

MySQL 學習 之 你還在用 TIMESTAMP 嗎?

目錄 1. 弊端1.1. 取值范圍1.2. 時區依賴1.3. 隱式轉換 2. 區別3. 解決 1. 弊端 1.1. 取值范圍 TIMESTAMP 的取值范圍為 1970-01-01 00:00:01 UTC 到 2038-01-19 03:14:07 UTC&#xff0c;超出范圍的數據會被強制歸零或觸發異常?。 具體表現為在基金債券等業務中&#xff0…

java中字節和字符有何區別,為什么有字節流和字符流?

在Java中&#xff0c;字節&#xff08;byte&#xff09;和字符&#xff08;char&#xff09;是兩種不同的數據類型&#xff0c;它們的主要區別在于所表示的數據單位、用途以及編碼方式,字節流和字符流的區分就是為了解決編碼問題。 字節&#xff08;byte&#xff09;&#xff…

伴隨矩陣 線性代數

伴隨矩陣的定義 伴隨矩陣的作用是什么&#xff1f;我們可以看到其伴隨矩陣乘上自己等于一個數&#xff08;自身的行列式&#xff09;乘以E&#xff0c;所以對于一個方陣來說&#xff0c;其逆矩陣就是自己的伴隨矩陣的倍數。 所以說伴隨矩陣的作用就是用來更好的求解逆矩陣的。…

百勝軟件獲邀走進華為,AI實踐經驗分享精彩綻放

在數字化浪潮席卷全球的當下&#xff0c;零售行業正經歷著深刻變革&#xff0c;人工智能技術成為重塑行業格局的關鍵力量。6月26日&#xff0c;“走進華為——智領零售&#xff0c;AI賦能新未來”活動在華為練秋湖研發中心成功舉辦。百勝軟件作為數字零售深耕者&#xff0c;攜“…

六種扎根理論的編碼方法

一、實境編碼 1.概念&#xff1a;實境編碼是一種基于參與者原生語言的質性編碼方法&#xff0c;其核心在于直接采用研究對象在訪談、觀察或文本中使用的原始詞匯、短語或獨特表達作為分析代碼。該方法通過保留數據的"原生態"語言形式&#xff08;如方言、隱喻、習慣用…

【Spring篇09】:制作自己的spring-boot-starter依賴1

文章目錄 1. Spring Boot Starter 的本質2. Starter 的模塊結構&#xff08;推薦&#xff09;3. 制作 xxx-spring-boot-autoconfigure 模塊3.1 添加必要的依賴3.2 編寫具體功能的配置類3.3 編寫自動化配置類 (AutoConfiguration)3.4 注冊自動化配置類 (.imports 或 spring.fact…

Qt6之qml自定義控件開發流程指南

Qt6之qml自定義控件開發流程指南 &#x1f6e0;? 一、基礎控件創建 定義 QML 文件 在工程中新建 QML 文件&#xff08;如 CustomButton.qml&#xff09;&#xff0c;文件名首字母大寫。 使用基礎組件&#xff08;如 Rectangle、Text&#xff09;構建控件邏輯&#xff0c;通過…

Vue簡介,什么是Vue(Vue3)?

什么是Vue&#xff1f; Vue是一款用于構建用戶界面的JavaScript框架。 它基于標準HTML、CSS和JavaScript構建&#xff0c;并提供了一套聲明式的、組件化的編程模型&#xff0c;幫助你高效地開發用戶界面。無論是簡單的還是復雜地界面&#xff0c;Vue都可以勝任。 聲明式渲染…

從零開始構建Airbyte數據管道:PostgreSQL到BigQuery實戰指南

作為數據工程師&#xff0c;ETL&#xff08;Extract, Transform, Load&#xff09;流程是日常工作的核心。然而&#xff0c;構建和維護數據管道往往耗時且復雜。幸運的是&#xff0c;開源工具Airbyte提供了一種更便捷的解決方案——它支持350預構建連接器&#xff0c;允許通過無…

JavaScript的初步學習

目錄 JavaScript簡介 主要特點 主要用途 JavaScript的基本特性 JavaScript的引入方式 1. 內聯方式 (Inline JavaScript) 2. 內部方式 (Internal JavaScript / Embedded JavaScript) 3. 外部方式 (External JavaScript) JavaScript的語法介紹 1.書寫語法 2.輸出語句 3.…

洛谷P1379 八數碼難題【A-star】

P1379 八數碼難題 八數碼難題首先要進行有解性判定&#xff0c;避免無解情況下盲目搜索浪費時間。 有解性判定 P10454 奇數碼問題 題意簡述 在一個 n n n \times n nn 的網格中進行&#xff0c;其中 n n n 為奇數&#xff0c; 1 1 1 個空格和 [ 1 , n 2 ? 1 ] [1,n^2…

MySQL Buffer Pool 深度解析:從架構設計到性能優化(附詳細結構圖解)

在 MySQL 數據庫的世界里&#xff0c;有一個決定性能上限的"神秘倉庫"——Buffer Pool。它就像超市的貨架&#xff0c;把最常用的商品&#xff08;數據&#xff09;放在最方便拿取的地方&#xff0c;避免每次都要去倉庫&#xff08;磁盤&#xff09;取貨。今天我們就…

使用numpy的快速傅里葉變換的一些問題

離散傅里葉變換&#xff08;DFT&#xff09;的頻率&#xff08;或波數&#xff09;確實主要由采樣點數和物理步長決定。 最高波數和最小波長的乘積是1。單位長度內波的周期數。 &#xff08;注意角波數是 k 2 π λ k \frac{2 \pi}{\lambda} kλ2π?&#xff09; 使用numpy…

DVWA靶場通關筆記-CSRF(High級別)

目錄 一、CSRF Token 二、代碼審計&#xff08;High級別&#xff09; 1、滲透準備 2、源碼分析 三、滲透實戰 1、滲透準備 2、修改URL重放失敗 3、burpsuite嘗試重放失敗 4、安裝CSRF Token Tracker 5、安裝logger插件 6、配置CSRF Token Tracker 7、bp再次重放報文…

Redis實戰:數據安全與性能保障

數據安全 持久化策略 RDB持久化&#xff1a;通過創建快照將內存中的數據寫入到磁盤上的RDB文件中。可以在配置文件中設置save參數來指定在多少秒內有多少次寫操作時觸發快照保存。例如&#xff0c;save 900 1表示900秒內至少有1次寫操作時保存快照。 AOF持久化&#xff1a;將每…

人臉活體識別3:C/C++實現實時眨眼、張嘴、點頭、搖頭檢測

> 當AI能識破照片與真人的區別,我們才真正跨入生物識別安全時代 --- ### 一、活體檢測:數字世界的守門人 **傳統人臉識別的致命缺陷**: - 高清照片欺騙成功率 > 85% - 視頻回放攻擊成本 < $50 - 3D面具破解率高達72% **我們的解決方案**: ```mermaid graph …