React由Meta公司研發,用于構建Web和原生交互界面的庫。
React 官方中文文檔
查看JSX
(一)React組件
-
用戶界面的一部分,通俗的來講,最小的元素組成的單元,可以實現部分邏輯與功能
-
房子的門就可以看成一個組件,由木板和木方組成,有一定功能和作用,多個組件組合就可以形成房子了。
-
組件之間可以相互嵌套,重復使用
React組件
-
React中,組件就是一個首字母大寫的函數,內部存放組件的邏輯和視圖UI,使用組件只需將組件當成標簽寫即可
-
組件也不能返回多個 JSX 標簽,必須將它們包裹到一個共享的父級中,比如
<div>...</div>
或使用空的<>...</>
包裹: -
組件只負責自己的任務。 它不會更改在該函數調用前就已存在的對象或變量。
-
組件輸入相同,則輸出相同。 給定相同的輸入,組件應該總是返回相同的 JSX。
function MyButton() {return(<button >點了我</button>);
}const App = () => {return <MyButton ></MyButton>;};
Hook(鉤子函數)
hook是特殊的函數,搭配函數組件一起使用,使其功能更強大
hook使用規則
- 只能在頂層調用Hooks,不要在循環、條件判斷或者嵌套函數中調用。
- 只能在React函數組件或自定義Hook中調用Hooks。
(二)useState
為組件設置state可以讓組件擁有記憶,完成交互
特點
-
State 變量 用于保存渲染間的數據。
-
State setter 函數 更新變量并觸發 React 再次渲染組件
-
只能在組件或[自定義 Hook]的最頂層調用
快速入門
-
在文件頂部導入useState
import { useState } from 'react';
-
創建一個useState
const [index, setIndex] = useState(0);
useState
的唯一參數是 state 變量的初始值
useState細節理解
-
狀態更新是異步的
React 會將多個狀態更新合并,以提高性能。因此,狀態更新不會立即生效,而是會在下一次渲染時生效。
-
批量更新
在 React 的事件處理函數中,多個狀態更新會被批量處理,只觸發一次重新渲染。
useState更新原理
State通過setState更新,實際上State只是可讀的,setState更新只是將原來的值替換掉,而并非修改原數據
-
更新State對象
通過
...對象展開符
快速跟新對象const [user, setUser] = useState({ name: 'Alice', age: 25 });// 更新年齡 const updateAge = () => {setUser(prev => ({ ...prev, age: 26 })); };
-
更新State數組
注意:即使你拷貝了數組,你還是不能直接修改其內部的元素,因為數組拷貝是淺拷貝
避免使用 (會改變原始數組) 推薦使用 (會返回一個新數組) 添加元素 push
,unshift
concat
,[...arr]
展開語法刪除元素 pop
,shift
,splice
filter
,slice
替換元素 splice
,arr[i] = ...
賦值map
排序 reverse
,sort
先將數組復制一份,再排序
受控表單
使用react組件狀態控制表單
const App = () => {const [value, setValue] = useState('');return (<><inputvalue={value}onChange={(e)=>setValue(e.target.value)}type="text"/></>)
};
如何構建State
- 先根據react數據驅動視圖的特點,頁面哪些UI狀態改變會導致界面改變,就給它定義個State控制界面更新
- 然后根據構建State原則對State進行優化
構建State的原則
狀態提升
要從多個子組件收集數據,或讓兩個子組件相互通信,請改為在其父組件中聲明共享 state。父組件可以通過 props 將該 state 傳回給子組件。這使子組件彼此同步并與其父組件保持同步。
(三)props
React中使用props進行參數傳遞
//value=0進行默認賦值,當value=null就讀取默認值0
function Square({value=0, onSquareClick}) {return (<button className="square" onClick={onSquareClick}>{value}</button>);
}export default function App(){return(<div className="board-row"><Square value="1" onSquareClick={() => handleClick(0)}/><Square value="2" onSquareClick={() => handleClick(1)}/><Square value="3" onSquareClick={() => handleClick(2)}/></div>);
}
children屬性
props.children
是一個特殊的屬性,用于傳遞組件包裹的子元素(子節點)
children
可以是以下任意類型:
- 字符串:直接作為文本內容。
- React 元素:如
<div>
、自定義組件等。 - 數組:多個子元素組成的數組。
- 函數:通過函數模式實現動態渲染(即 Render Props 模式)。
- 空值:
null
、undefined
或false
(不會被渲染)。
<Child><h1>標題</h1><p>段落</p>
</Child>// Child 組件內部:
function Child(props) {return <div>{props.children}</div>; // 同時渲染標題和段落
}
(四)UseContext跨層傳遞參數
Context是一種跨組件層級傳遞數據的機制,適合全局數據(如用戶信息、主題、語言等),區別于props逐層傳遞。
- Provider:通過
<MyContext.Provider value={data}>
向子組件樹傳遞數據。 - Consumer:通過
useContext(MyContext)
直接獲取最近一層 Provider 提供的數據。
示例
假設有 3 層組件:Parent
→ Child
→ Grandchild
,需要將用戶信息從 Parent
直接傳遞到 Grandchild
,無需經過 Child
中轉。
// UserContext.js
import { createContext } from 'react';export const UserContext = createContext({ name: '默認用戶', age: 0
});
// Parent.jsx
import { UserContext } from './UserContext';
import Child from './Child';const Parent = () => {const user = { name: "小明", age: 20 };return (<UserContext.Provider value={user}><div><h2>Parent 組件</h2><Child /> {/* 子組件不需要傳遞任何 props! */}</div></UserContext.Provider>);
};
// Child.jsx
import Grandchild from './Grandchild';const Child = () => {return (<div><h3>Child 組件</h3><Grandchild /> {/* 同樣無需傳遞 props */}</div>);
};
// Grandchild.jsx
import { useContext } from 'react';
import { UserContext } from './UserContext';const Grandchild = () => {const user = useContext(UserContext); // 直接獲取數據return (<div><h4>Grandchild 組件</h4><p>用戶名:{user.name}</p><p>年齡:{user.age}</p></div>);
};
(五)UseReducer集中狀態管理
useReducer – React 中文文檔
const [state, dispatch] = useReducer(reducer, initialState)
useReducer類似useState管理組件狀態,而UseReudcer集中狀態管理,管理方式類似“告訴reducer函數用戶進行了什么操作“
參數
- initialState:初始化狀態
- reducer函數:負責集中管理更新狀態(組件狀態更新就是在這里面)
返回值
- state:目前狀態
- dispatch函數:主要負責記錄用戶進行了什么操作并記錄值,比如點擊更新按鈕、點擊刪除按鈕等
如何將State狀態遷移至Reducer中
用State進行狀態管理的Todo清單
function TodoList() {const [todos, setTodos] = useState([]);const [input, setInput] = useState('');const addTodo = () => {setTodos([...todos, input]);setInput('');};return (<div><inputtype="text"value={input}onChange={(e) => setInput(e.target.value)}/><button onClick={addTodo}>Add Todo</button><ul>{todos.map((todo, index) => (<li key={index}>{todo}</li>))}</ul></div>);
}
用Reducer進行狀態管理的Todo清單
const initialState = {todos: [],input: '',
};function reducer(state, action) {switch (action.type) {case 'updateInput':return { ...state, input: action.payload };case 'addTodo':return { ...state, todos: [...state.todos, state.input], input: '' };default:return state;}
}function TodoList() {const [state, dispatch] = useReducer(reducer, initialState);return (<div><inputtype="text"value={state.input}onChange={(e) => dispatch({ type: 'updateInput', payload: e.target.value })}/><button onClick={() => dispatch({ type: 'addTodo' })}>Add Todo</button><ul>{state.todos.map((todo, index) => (<li key={index}>{todo}</li>))}</ul></div>);
}
(六)性能提升
React.memo
用memo包裹的組件擁有記憶緩存,當props沒有改變該組件不會重新渲染
React.memo(function MyComponent(props){},可選參數)
特點:
- props與上一次相同(是同一個),如果props是對象或者數組,重新創建一個相同的新的,React也會認為不同,所以通常useMemo、useCallback一起使用
- useContext多層傳參也會導致Memo包裹的組件重新渲染,所以一般在外層接收作為props傳入
useMemo
useMemo(函數,依賴數組),useMemo組成通常是函數和依賴數組,可以在每次重新渲染緩存計算結果(函數的返回值)
-
函數是任意不帶參的函數(一般用箭頭函數),可返回任意值
-
依賴數組:一般是props或useState
const TodoList=useMemo(()=>todo(tab,list),[tab,list])
useCallback
useCallback用來緩存函數,當依賴數組不發生改變時,函數不變,效果類似useMemo
useCallback(fn,dependencies)
區別useMemo和useCallback
區別 | useMemo | useCallback |
---|---|---|
主要用途 | 用于記憶計算結果 | 用于記憶定義函數 |
返回值 | 返回計算結果 | 返回記憶函數 |
使用場景 | 避免昂貴的計算 | 避免不必要的子組件重新渲染 |