作為一名 React 開發(fā)者,你可能會面臨下面幾個(gè)問題:
為解決上述問題,下面介紹五種 React 組件設(shè)計(jì)模式,并對比它們的優(yōu)缺點(diǎn)。
復(fù)合組件模式是一種通過將多個(gè)簡單組件組合在一起創(chuàng)建更復(fù)雜組件的方法。這種模式使得組件的邏輯分離,每個(gè)簡單組件負(fù)責(zé)特定的功能。通過復(fù)合組件,可以輕松構(gòu)建可復(fù)用的、功能完備的組件。
如果想要設(shè)計(jì)一個(gè)定制化程度高,API方便理解的組件,可以考慮這個(gè)模式,這種模式不會出現(xiàn)多層Props傳遞的情況。
import React, { useState } from 'react';// 基礎(chǔ)按紐組件const Button = ({ label, onClick }) => ( <button onClick={onClick}>{label}</button>);// 基礎(chǔ)文本組件const TextBox = ({ value, onChange }) => ( <input type="text" value={value} onChange={onChange} />);// 復(fù)合組件const LoginPanel = () => { const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const handleLogin = () => { // 實(shí)現(xiàn)登錄邏輯 console.log(`Logging in with ${username} and ${password}`); }; return ( <div className="login-panel"> <TextBox value={username} onChange={(e) => setUsername(e.target.value)} /> <TextBox value={password} onChange={(e) => setPassword(e.target.value)} /> <Button label="Login" onClick={handleLogin} /> </div> );};// 使用示例const App = () => { return ( <LoginPanel /> );};export default App;
在這個(gè)例子中,LoginPanel 是一個(gè)復(fù)合組件,它包含了兩個(gè)基本組件 TextBox 和一個(gè)帶有登錄邏輯的 Button。
優(yōu)點(diǎn):
適用場景:
受控組件模式就是將組件轉(zhuǎn)換為受控組件,通過直接修改 Props 影響組件內(nèi)部的狀態(tài),一般在表單組件中比較常用。
import React, { useState } from 'react';const Button = ({ label, onClick }) => ( <button onClick={onClick}>{label}</button>);const TextBox = ({ value, onChange }) => ( <input type="text" value={value} onChange={onChange} />);// 受控組件模式的復(fù)合組件const ControlledLoginPanel = () => { const [loginData, setLoginData] = useState({ username: '', password: '' }); const handleInputChange = (e) => { const { name, value } = e.target; setLoginData((prevData) => ({ ...prevData, [name]: value, })); }; const handleLogin = () => { // 實(shí)現(xiàn)登錄邏輯 console.log(`Logging in with ${loginData.username} and ${loginData.password}`); }; return ( <div className="login-panel"> <TextBox value={loginData.username} onChange={handleInputChange} /> <TextBox value={loginData.password} placeholder="Password" /> <Button label="Login" onClick={handleLogin} /> </div> );};// 使用示例const App = () => { return ( <ControlledLoginPanel /> );};export default App;
在這個(gè)例子中,ControlledLoginPanel 組件就是一個(gè)受控組件的例子,其中的輸入框的值由 React 狀態(tài)管理。
優(yōu)點(diǎn):
適用場景:
自定義Hooks模式是一種將組件邏輯提取為可重用的函數(shù)的方法。將主要的邏輯轉(zhuǎn)移到一個(gè)Hooks中。用戶可以訪問這個(gè)Hooks,并公開了幾個(gè)內(nèi)部邏輯(狀態(tài)、處理程序) ,使用戶能夠更好地控制組件。
import React, { useState } from 'react';const Button = ({ label, onClick }) => ( <button onClick={onClick}>{label}</button>);const TextBox = ({ value, onChange, placeholder }) => ( <input type="text" value={value} onChange={onChange} placeholder={placeholder} />);// 自定義 Hook,處理登錄表單邏輯const useLoginForm = () => { const [loginData, setLoginData] = useState({ username: '', password: '' }); const handleInputChange = (e) => { const { name, value } = e.target; setLoginData((prevData) => ({ ...prevData, [name]: value, })); }; const handleLogin = () => { // 在這里實(shí)現(xiàn)登錄邏輯 console.log(`使用用戶名 ${loginData.username} 和密碼 ${loginData.password} 登錄`); }; return { loginData, handleInputChange, handleLogin, };};// 在組件中使用自定義 Hookconst ControlledLoginPanel = () => { const { loginData, handleInputChange, handleLogin } = useLoginForm(); return ( <div className="login-panel"> <TextBox value={loginData.username} onChange={handleInputChange} placeholder="用戶名" /> <TextBox value={loginData.password} onChange={handleInputChange} placeholder="密碼" /> <Button label="登錄" onClick={handleLogin} /> </div> );};// 使用示例const App = () => { return ( <ControlledLoginPanel /> );};export default App;
在這個(gè)例子中,我們將與登錄表單相關(guān)的狀態(tài)和邏輯抽離到一個(gè)自定義 useLoginForm Hook 中。使得 ControlledLoginPanel 組件更專注于渲染 UI,減少了狀態(tài)和事件處理邏輯的混雜。
優(yōu)點(diǎn):
模式 3 中的自定義Hooks提供了很好的控制方式;但是比較難以集成,使用者需要按照組件提供的Hooks與State相結(jié)合進(jìn)行編寫邏輯,提高了集成的復(fù)雜度。Props Getters模式則是通過簡化這一過程來實(shí)現(xiàn)。Getter是一個(gè)返回多個(gè)屬性的函數(shù),它具有有意義的名稱,使得開發(fā)者能夠清楚地知道哪個(gè)Getter對應(yīng)于哪個(gè)JSX元素。
import React, { useState } from 'react';const Button = ({ getLabel, handleClick }) => ( <button onClick={handleClick}>{getLabel()}</button>);const TextBox = ({ getValue, onChange, placeholder }) => ( <input type="text" value={getValue()} onChange={onChange} placeholder={placeholder} />);const ControlledLoginPanel = ({ getUsernameProps, getPasswordProps, handleLogin }) => { return ( <div className="login-panel"> <TextBox {...getUsernameProps()} placeholder="Username" /> <TextBox {...getPasswordProps()} placeholder="Password" /> <Button getLabel={() => 'Login'} handleClick={handleLogin} /> </div> );};// 使用 Props Getters 模式的 Hooksconst useLoginForm = () => { const [loginData, setLoginData] = useState({ username: '', password: '' }); const handleInputChange = (name) => (e) => { const { value } = e.target; setLoginData((prevData) => ({ ...prevData, [name]: value, })); }; const handleLogin = () => { // 實(shí)現(xiàn)登錄邏輯 console.log(`Logging in with ${loginData.username} and ${loginData.password}`); }; const getUsernameProps = () => ({ getValue: () => loginData.username, onChange: handleInputChange('username'), }); const getPasswordProps = () => ({ getValue: () => loginData.password, onChange: handleInputChange('password'), }); return { getUsernameProps, getPasswordProps, handleLogin, };};// 使用示例const App = () => { const { getUsernameProps, getPasswordProps, handleLogin } = useLoginForm(); return ( <ControlledLoginPanel getUsernameProps={getUsernameProps} getPasswordProps={getPasswordProps} handleLogin={handleLogin} /> );};export default App;
在這個(gè)例子中,我們基于模式 3 進(jìn)行了改造,把 ControlledLoginPanel 組件需要的 Props 通過函數(shù)的方式進(jìn)行獲取,以實(shí)現(xiàn)更靈活、更簡便的組件復(fù)用。
優(yōu)點(diǎn):
缺點(diǎn):
適用場景:
State Reducer 模式是一種通過將組件的狀態(tài)更新邏輯委托給一個(gè)函數(shù),實(shí)現(xiàn)更靈活的狀態(tài)管理方式。這種模式通常在處理復(fù)雜的狀態(tài)邏輯時(shí)非常有用。
import React, { useState } from 'react';const TextInput = ({ getInputProps }) => { const inputProps = getInputProps(); return <input {...inputProps} />;};const StateReducerExample = () => { // 初始狀態(tài)為一個(gè)空字符串 const [inputValue, setInputValue] = useState(''); // stateReducer 函數(shù)用于處理狀態(tài)的變化 const stateReducer = (state, changes) => { // 使用 switch case 處理不同的狀態(tài)變化情況 switch (Object.keys(changes)[0]) { // 如果變化的是 value 屬性 case 'value': // 如果輸入的字符數(shù)量超過 10 個(gè),則不允許變化 if (changes.value.length > 10) { return state; } break; // 可以添加其他 case 處理不同的狀態(tài)變化 default: break; } // 返回新的狀態(tài) return { ...state, ...changes }; }; // 獲取傳遞給子組件的 props const getInputProps = () => { return { value: inputValue, // 在輸入框變化時(shí)調(diào)用 stateReducer 處理狀態(tài)變化 onChange: (e) => setInputValue(stateReducer({ value: e.target.value })), }; }; return ( <div> <h3>State Reducer Example</h3> {/* 將獲取的 props 傳遞給 TextInput 組件 */} <TextInput getInputProps={getInputProps} /> </div> );};export default StateReducerExample;
在這個(gè)例子中,StateReducerExample 組件包含一個(gè)輸入框,通過 getInputProps 函數(shù)將輸入框的值和變化處理邏輯傳遞給 TextInput 組件。stateReducer 函數(shù)處理狀態(tài)的變化,確保輸入的字符數(shù)量不超過 10 個(gè)。
優(yōu)點(diǎn):
缺點(diǎn):
適用場景:
通過這 5 種 React 組件設(shè)計(jì)模式,我們對“控制度”和“復(fù)雜度”有了更清晰的認(rèn)識,下圖是復(fù)雜度和控制度的一個(gè)趨勢圖。
圖片
總體來說,設(shè)計(jì)的組件越靈活,功能也就越強(qiáng)大,復(fù)雜度也會更高。作為開發(fā)人員,建議大家根據(jù)自己的業(yè)務(wù)邏輯以及使用人群,靈活使用以上的設(shè)計(jì)模式。
React 組件設(shè)計(jì)模式
本文鏈接:http://www.tebozhan.com/showinfo-26-59689-0.html淺析五種 React 組件設(shè)計(jì)模式
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com