React Native從類組件到函數(shù)組件詳解
1. 發(fā)展趨勢(shì)
React Native社區(qū)中的趨勢(shì)是朝向使用函數(shù)組件(Functional Components)和Hooks的方向發(fā)展,而不是使用類組件(Class Components)。
React Native自推出Hooks API以來,函數(shù)組件和Hooks的使用變得更加普遍和推薦。Hooks提供了更簡(jiǎn)潔、可讀性更高的代碼,并且在狀態(tài)管理、生命周期等方面提供了更強(qiáng)大的功能。使用Hooks可以更容易地共享邏輯和狀態(tài)邏輯,而無需使用類組件的復(fù)雜結(jié)構(gòu)。
以下是一些關(guān)于為什么React Native社區(qū)更傾向于使用函數(shù)組件和Hooks的理由:
- 可讀性和簡(jiǎn)潔性: 函數(shù)組件通常比類組件更短,更易于閱讀和理解。Hooks的引入使得在函數(shù)組件中管理狀態(tài)和副作用變得更為直觀。
- 邏輯復(fù)用: Hooks使得邏輯的復(fù)用更加容易。你可以使用自定義Hooks將組件之間的邏輯進(jìn)行抽象和共享,而不需要使用高階組件或渲染屬性。
- 更直觀的副作用處理: 使用useEffect等Hooks來處理副作用相對(duì)于類組件中的生命周期方法更為直觀。
- 更容易集成現(xiàn)代JavaScript特性: 使用函數(shù)組件和Hooks可以更容易地與ES6+和TypeScript等現(xiàn)代JavaScript特性集成。
- 更好的性能優(yōu)化: Hooks使得React能夠更好地進(jìn)行性能優(yōu)化,并且React Native的未來版本也更加注重性能。
2. Hooks vs Class
Hooks 提供了在函數(shù)組件中執(zhí)行副作用和訪問狀態(tài)的能力。
下面是一些常見的 Hooks 及其在類組件中對(duì)應(yīng)的生命周期方法:
1.useState
- setState
:
- 函數(shù)組件: 使用 useState 來聲明和更新狀態(tài)。
- 類組件: 使用 this.setState 來更新狀態(tài)。
2.useEffect
- componentDidMount
, componentDidUpdate
, componentWillUnmount
:
函數(shù)組件: 使用 useEffect
來執(zhí)行副作用,可以模擬生命周期方法的行為。
類組件:
componentDidMount
: 在組件掛載后調(diào)用。componentDidUpdate
: 在組件更新后調(diào)用。componentWillUnmount
: 在組件卸載前調(diào)用。
useEffect(() => { // componentDidMount 和 componentDidUpdate 的邏輯 return () => { // componentWillUnmount 的邏輯 }; }, [dependencies]);
3.useContext
- contextType
:
- 函數(shù)組件:使用 useContext 來訪問 React 上下文。
- 類組件:使用 contextType 來訪問 React 上下文。
4.useReducer
- setState
和 this.setState
:
- 函數(shù)組件: 使用 useReducer 來管理復(fù)雜狀態(tài)邏輯。
- 類組件: 可以使用 setState 或 this.setState,但 useReducer 更適合處理復(fù)雜狀態(tài)邏輯。
5.useCallback
- shouldComponentUpdate
:
- 函數(shù)組件: 使用
useCallback
來記憶回調(diào)函數(shù),以防止每次重新渲染時(shí)重新創(chuàng)建它。 - 類組件: 在
shouldComponentUpdate
中進(jìn)行優(yōu)化,防止不必要的渲染。
6.useMemo
- shouldComponentUpdate
:
- 函數(shù)組件: 使用
useMemo
來記憶計(jì)算昂貴的計(jì)算結(jié)果。 - 類組件: 在
shouldComponentUpdate
中進(jìn)行優(yōu)化,防止不必要的渲染。
這些是一些常見的 Hooks,它們?yōu)楹瘮?shù)組件提供了類似于類組件生命周期方法的功能。使用 Hooks 可以更清晰地組織和重用邏輯。需要注意的是,使用 Hooks 時(shí),每個(gè) Hook 都是相互獨(dú)立的,而類組件中的生命周期方法可能會(huì)涵蓋多個(gè)生命周期階段。
2.1 useState
useState
是 React Hooks 中用于在函數(shù)組件中添加狀態(tài)的關(guān)鍵之一。它允許你在函數(shù)組件中添加和管理狀態(tài),而不需要使用類組件。
useState
返回一個(gè)數(shù)組,其中包含兩個(gè)元素:當(dāng)前狀態(tài)的值和一個(gè)更新狀態(tài)的函數(shù)。
下面是 useState
的基本用法:
import React, { useState } from 'react'; function MyComponent() { // 使用 useState 定義一個(gè)狀態(tài)變量,初始值為 'initialValue' const [state, setState] = useState('initialValue'); return ( <div> <p>Current State: {state}</p> {/* 使用 setState 函數(shù)來更新狀態(tài) */} <button onClick={() => setState('newValue')}> Update State </button> </div> ); } export default MyComponent;
在上面的例子中,useState
被調(diào)用并傳入初始狀態(tài) 'initialValue'
,返回的數(shù)組包含當(dāng)前狀態(tài)值 state
和更新狀態(tài)的函數(shù) setState
。通過點(diǎn)擊按鈕,可以觸發(fā) setState
函數(shù)來更新狀態(tài)。
useState
的基本用法包括:
- 定義狀態(tài): 調(diào)用 useState 來聲明一個(gè)狀態(tài)變量,并傳入初始值。
- 獲取當(dāng)前狀態(tài)值: 使用返回的數(shù)組的第一個(gè)元素(例如,state)來獲取當(dāng)前狀態(tài)的值。
- 更新狀態(tài): 使用返回的數(shù)組的第二個(gè)元素(例如,setState)來更新狀態(tài)。setState 函數(shù)接受新的狀態(tài)值作為參數(shù)。
請(qǐng)注意,useState
可以在組件中多次調(diào)用,以添加多個(gè)狀態(tài)變量。每個(gè)狀態(tài)變量都有自己獨(dú)立的 setState
函數(shù)。
import React, { useState } from 'react'; function MyComponent() { const [count, setCount] = useState(0); const [text, setText] = useState(''); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}> Increment Count </button> <p>Text: {text}</p> <input type="text" value={text} onChange={(e) => setText(e.target.value)} /> </div> ); } export default MyComponent;
在上面的例子中,MyComponent 組件有兩個(gè)狀態(tài)變量 count
和 text
,每個(gè)都有自己的 setState
函數(shù)。
2.2 useEffect
useEffect
是 React Hooks 中用于處理副作用的關(guān)鍵之一。它在函數(shù)組件中提供了執(zhí)行副作用的能力。useEffect
接受兩個(gè)參數(shù):
- 一個(gè)函數(shù),包含需要執(zhí)行的副作用代碼。
- 一個(gè)可選的依賴數(shù)組,用于指定在依賴項(xiàng)發(fā)生變化時(shí)才重新運(yùn)行 useEffect。
import React, { useEffect } from 'react'; function MyComponent() { // 在組件掛載后執(zhí)行一次 useEffect(() => { // 執(zhí)行副作用的代碼 // 清理函數(shù)(componentWillUnmount 的替代) return () => { // 在組件卸載前執(zhí)行清理邏輯 }; }, [dependencies]); // 依賴項(xiàng)數(shù)組 return ( // 組件的 JSX ); } export default MyComponent;
- Effect 函數(shù): 第一個(gè)參數(shù)是一個(gè)函數(shù),包含需要在每次渲染后執(zhí)行的副作用代碼。這個(gè)函數(shù)可以返回一個(gè)清理函數(shù)(cleanup function),用于在組件卸載時(shí)執(zhí)行清理邏輯,類似于 componentWillUnmount。
- 依賴項(xiàng)數(shù)組: 第二個(gè)參數(shù)是一個(gè)數(shù)組,包含影響副作用執(zhí)行的變量。如果依賴項(xiàng)數(shù)組中的任何一個(gè)變量發(fā)生變化,
useEffect
就會(huì)重新運(yùn)行。如果省略依賴項(xiàng)數(shù)組,副作用將在每次組件渲染時(shí)都運(yùn)行。
以下是一些 useEffect 的常見用法:
- 只在組件掛載時(shí)執(zhí)行副作用:
useEffect(() => { // 執(zhí)行副作用的代碼 return () => { // 在組件卸載前執(zhí)行清理邏輯 }; }, []);
- 在特定依賴項(xiàng)變化時(shí)執(zhí)行副作用:
useEffect(() => { // 執(zhí)行副作用的代碼 return () => { // 在特定依賴項(xiàng)變化時(shí)執(zhí)行清理邏輯 }; }, [dependency1, dependency2]);
- 執(zhí)行異步操作:
useEffect(() => { const fetchData = async () => { try { // 異步操作,比如從 API 獲取數(shù)據(jù) const result = await fetchDataFromApi(); // 處理結(jié)果 } catch (error) { // 處理錯(cuò)誤 } }; fetchData(); return () => { // 在組件卸載前執(zhí)行清理邏輯 }; }, [dependency]);
useEffect
的使用取決于具體的需求,可以根據(jù)需要執(zhí)行副作用,并確保在組件卸載前進(jìn)行必要的清理。
2.3 useContext
useContext
是 React Hooks 中用于訪問 React 上下文的鉤子。它允許你在函數(shù)組件中訂閱 React 上下文的值,而無需使用 Context.Consumer
。
下面是 useContext
的基本用法:
- 創(chuàng)建上下文: 使用
React.createContext
創(chuàng)建一個(gè)上下文對(duì)象。 - 在頂層組件提供上下文的值: 使用
Context.Provider
在組件樹的某個(gè)位置提供上下文的值。 - 在子組件中使用
useContext
: 在需要訪問上下文的子組件中使用useContext
來獲取上下文的值。
以下是一個(gè)簡(jiǎn)單的例子:
import React, { createContext, useContext } from 'react'; // 創(chuàng)建一個(gè)上下文對(duì)象 const MyContext = createContext(); // 在頂層組件提供上下文的值 function MyProvider({ children }) { const contextValue = 'Hello from Context'; return ( <MyContext.Provider value={contextValue}> {children} </MyContext.Provider> ); } // 在子組件中使用 useContext 獲取上下文的值 function MyComponent() { const contextValue = useContext(MyContext); return <p>{contextValue}</p>; } // 在應(yīng)用的頂層組件中使用 MyProvider 包裹子組件 function App() { return ( <MyProvider> <MyComponent /> </MyProvider> ); } export default App;
如果組件分別在不同的組件中, 則可以定義一個(gè)文件導(dǎo)出定義的 context
:
import { createContext } from 'react'; const MyContext = createContext(); export default MyContext;
2.4 useReducer
useReducer
是 React Hooks 中用于管理復(fù)雜狀態(tài)邏輯的鉤子。它提供了一種可預(yù)測(cè)的方式來更新狀態(tài),尤其適用于處理具有多個(gè)可能操作的狀態(tài)。使用 useReducer
時(shí),你需要定義一個(gè) reducer 函數(shù),該函數(shù)負(fù)責(zé)處理不同的操作,并返回新的狀態(tài)。
下面是 useReducer 的基本用法:
- 定義 reducer 函數(shù): 創(chuàng)建一個(gè)接受當(dāng)前狀態(tài)和操作的函數(shù),根據(jù)操作類型返回新的狀態(tài)。reducer 函數(shù)的格式為
(state, action) => newState
。 - 使用
useReducer
: 在組件中調(diào)用useReducer
并傳入 reducer 函數(shù)和初始狀態(tài)。 - 得到當(dāng)前狀態(tài)和 dispatch 函數(shù):
useReducer
返回一個(gè)包含當(dāng)前狀態(tài)和 dispatch 函數(shù)的數(shù)組。 - dispatch 操作: 調(diào)用 dispatch 函數(shù)并傳入一個(gè)操作對(duì)象,reducer 將根據(jù)操作類型來更新狀態(tài)。
以下是一個(gè)簡(jiǎn)單的例子:
import React, { useReducer } from 'react'; // 定義 reducer 函數(shù) const reducer = (state, action) => { switch (action.type) { case 'INCREMENT': return { count: state.count + 1 }; case 'DECREMENT': return { count: state.count - 1 }; default: return state; } }; // 使用 useReducer function Counter() { const [state, dispatch] = useReducer(reducer, { count: 0 }); return ( <div> <p>Count: {state.count}</p> <button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button> <button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button> </div> ); } export default Counter;
在上面的例子中,reducer
函數(shù)接收當(dāng)前狀態(tài)和操作,根據(jù)操作類型更新狀態(tài)。useReducer
返回一個(gè)包含當(dāng)前狀態(tài)和 dispatch 函數(shù)的數(shù)組。通過調(diào)用 dispatch 函數(shù),并傳入包含 type
屬性的操作對(duì)象,可以觸發(fā) reducer 來更新狀態(tài)。
useReducer
還支持傳入一個(gè)可選的初始化函數(shù),用于計(jì)算初始狀態(tài),例如:
const initialState = { count: 0 }; const init = (initialState) => { return { count: initialState.count * 2 }; }; const [state, dispatch] = useReducer(reducer, initialState, init);
在這個(gè)例子中,init
函數(shù)接收初始狀態(tài),并返回實(shí)際的初始狀態(tài)。這可以是有用的,例如在初始狀態(tài)需要基于某些計(jì)算的情況下。
使用 useReducer
的主要優(yōu)勢(shì)在于它使得狀態(tài)邏輯更加模塊化,特別是當(dāng)有多個(gè)操作可能影響狀態(tài)時(shí)。
2.5 useCallback
useCallback
是 React Hooks 中用于記憶回調(diào)函數(shù)的鉤子。它的主要作用是在依賴不變的情況下,返回一個(gè)記憶化的回調(diào)函數(shù),避免在每次渲染時(shí)創(chuàng)建新的回調(diào)函數(shù)。這有助于優(yōu)化性能,特別是在子組件中使用時(shí)。
基本的使用方式如下:
import React, { useCallback } from 'react'; function MyComponent({ onClick }) { // 使用 useCallback 包裹回調(diào)函數(shù) const memoizedCallback = useCallback( () => { // 回調(diào)函數(shù)的邏輯 console.log('Callback executed!'); }, // 依賴項(xiàng)數(shù)組 [/* dependencies */] ); return ( <button onClick={memoizedCallback}> Click me </button> ); } export default MyComponent;
在上面的例子中,useCallback
接收兩個(gè)參數(shù):一個(gè)回調(diào)函數(shù)和一個(gè)依賴項(xiàng)數(shù)組。它返回一個(gè)記憶化后的回調(diào)函數(shù) memoizedCallback
。如果依賴項(xiàng)數(shù)組中的值沒有發(fā)生變化,memoizedCallback
將保持相同的引用,從而避免在每次渲染時(shí)重新創(chuàng)建回調(diào)函數(shù)。
常見的用法包括:
- 避免子組件的不必要渲染: 在將回調(diào)函數(shù)傳遞給子組件時(shí),使用
useCallback
避免子組件不必要地重新渲染。
const memoizedCallback = useCallback( () => { // 回調(diào)函數(shù)的邏輯 }, [/* dependencies */] ); return <ChildComponent onClick={memoizedCallback} />;
- 作為依賴項(xiàng)傳遞給其他 Hook: 在使用其他 Hook 時(shí),將
useCallback
的記憶化回調(diào)函數(shù)作為依賴項(xiàng)傳遞。
useEffect(() => { // 使用 memoizedCallback 作為依賴項(xiàng) someHook(memoizedCallback); }, [memoizedCallback]);
- 避免在依賴項(xiàng)變化時(shí)觸發(fā) effect: 在使用
useEffect
時(shí),通過使用useCallback
避免在依賴項(xiàng)變化時(shí)觸發(fā) effect。
useEffect(() => { // 在 memoizedCallback 變化時(shí)執(zhí)行 effect }, [memoizedCallback]);
需要注意的是,過度使用 useCallback
可能會(huì)導(dǎo)致性能問題,因?yàn)槊總€(gè)記憶化的回調(diào)函數(shù)都需要額外的內(nèi)存。因此,只在確實(shí)有性能問題或需要時(shí)使用 useCallback
。
2.6 useMemo
useMemo
是 React Hooks 中用于記憶化計(jì)算結(jié)果的鉤子。它接受一個(gè)計(jì)算函數(shù)和依賴項(xiàng)數(shù)組,并返回計(jì)算結(jié)果的記憶化版本。這有助于避免在每次渲染時(shí)重新計(jì)算耗時(shí)的操作,提高性能。
基本的使用方式如下:
import React, { useMemo } from 'react'; function MyComponent({ data }) { // 使用 useMemo 記憶化計(jì)算結(jié)果 const memoizedResult = useMemo( () => { // 計(jì)算結(jié)果的邏輯 console.log('Computing result...'); return data.filter(item => item > 5); }, // 依賴項(xiàng)數(shù)組 [data] ); return ( <div> <p>Result: {memoizedResult}</p> </div> ); } export default MyComponent;
在上面的例子中,useMemo
接收兩個(gè)參數(shù):一個(gè)計(jì)算函數(shù)和一個(gè)依賴項(xiàng)數(shù)組。它返回一個(gè)記憶化后的計(jì)算結(jié)果 memoizedResult
。如果依賴項(xiàng)數(shù)組中的值沒有發(fā)生變化,memoizedResult
將保持相同的引用,從而避免在每次渲染時(shí)重新計(jì)算結(jié)果。
常見的用法包括:
- 優(yōu)化渲染性能: 避免在每次渲染時(shí)都執(zhí)行昂貴的計(jì)算,只在依賴項(xiàng)變化時(shí)重新計(jì)算。
const memoizedResult = useMemo( () => { // 昂貴的計(jì)算邏輯 }, [/* dependencies */] );
- 記憶化函數(shù): 當(dāng)需要在每次渲染時(shí)都返回一個(gè)新的函數(shù),但只有在依賴項(xiàng)變化時(shí)才創(chuàng)建新函數(shù)時(shí),可以使用
useMemo
記憶化函數(shù)。
const memoizedFunction = useMemo( () => { return () => { // 函數(shù)的邏輯 }; }, [/* dependencies */] );
- 避免重復(fù)計(jì)算: 當(dāng)某個(gè)計(jì)算結(jié)果僅在特定依賴項(xiàng)變化時(shí)才發(fā)生變化時(shí),使用
useMemo
避免重復(fù)計(jì)算。
const memoizedResult = useMemo( () => { // 僅在特定依賴項(xiàng)變化時(shí)才計(jì)算結(jié)果 }, [specificDependency] );
需要注意的是,過度使用 useMemo 可能會(huì)導(dǎo)致性能問題,因?yàn)槊總€(gè)記憶化的結(jié)果都需要額外的內(nèi)存。因此,只在確實(shí)有性能問題或需要時(shí)使用 useMemo
。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
React中g(shù)etDefaultProps的使用小結(jié)
React中的getDefaultProps功能允許開發(fā)者為類組件定義默認(rèn)屬性,提高組件的靈活性和容錯(cuò)性,本文介紹了getDefaultProps的作用、語法以及最佳實(shí)踐,并探討了其他替代方案,如函數(shù)組件中的默認(rèn)參數(shù)、高階組件和ContextAPI等,理解這些概念有助于提升代碼的可維護(hù)性和用戶體驗(yàn)2024-09-09React中使用Workbox進(jìn)行預(yù)緩存的實(shí)現(xiàn)代碼
Workbox是Google Chrome團(tuán)隊(duì)推出的一套 PWA 的解決方案,這套解決方案當(dāng)中包含了核心庫和構(gòu)建工具,因此我們可以利用Workbox實(shí)現(xiàn)Service Worker的快速開發(fā),本文小編給大家介紹了React中使用Workbox進(jìn)行預(yù)緩存的實(shí)現(xiàn),需要的朋友可以參考下2023-11-11React?Hooks中?useRef和useImperativeHandle的使用方式
這篇文章主要介紹了React?Hooks中?useRef和useImperativeHandle的使用方式,文中說明了useRef和useCallback一起使用,?可以解決閉包陷阱的問題,本文結(jié)合實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10TypeScript在React項(xiàng)目中的使用實(shí)踐總結(jié)
這篇文章主要介紹了TypeScript在React項(xiàng)目中的使用總結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04react native實(shí)現(xiàn)監(jiān)控手勢(shì)上下拉動(dòng)效果
這篇文章主要為大家詳細(xì)介紹了react native實(shí)現(xiàn)監(jiān)控手勢(shì)上下拉動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-05-05使用React18和WebSocket構(gòu)建實(shí)時(shí)通信功能詳解
WebSocket是一種在Web應(yīng)用中實(shí)現(xiàn)雙向通信的協(xié)議,它允許服務(wù)器主動(dòng)向客戶端推送數(shù)據(jù),而不需要客戶端發(fā)起請(qǐng)求,本文將探索如何在React?18應(yīng)用中使用WebSocket來實(shí)現(xiàn)實(shí)時(shí)通信,感興趣的可以了解下2024-01-01