如何在React逻辑冗余组件中应用SOLID原则与整洁代码
React中应用SOLID拆分卡片输入组件的实践方案
1. XML解析逻辑:抽成纯工具函数
完全可以把XML数据提取逻辑抽成独立的辅助工具函数,这类纯逻辑函数不依赖React状态,符合单一职责原则,属于通用辅助工具。
命名建议
命名要直观体现功能,比如:
parseCardXmlResponse(明确是解析卡片相关的XML响应)extractCardDataFromXml(强调从XML中提取卡片数据)
实现示例
把这类函数放在单独的工具文件中,比如src/utils/card.utils.js:
// src/utils/card.utils.js // 卡号验证函数也可以放这里 export function validateCardNumber(cardNumber) { // 具体验证逻辑:比如长度、格式校验 return cardNumber.length === 16 && /^\d+$/.test(cardNumber); } // XML解析函数 export function parseCardXmlResponse(xmlString) { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(xmlString, "text/xml"); // 提取核心卡片数据 const cardNumber = xmlDoc.querySelector("CardNumber")?.textContent || ""; const cardBalance = xmlDoc.querySelector("Balance")?.textContent || "0"; const price = calculateCardPrice(cardBalance); return { cardNumber, cardBalance, price }; } // 价格计算函数单独拆分 export function calculateCardBalance(balance) { // 自定义价格计算逻辑 return parseFloat(balance) * 1.1; }
2. 拆分useCard Hook:聚焦状态与流程协调
原Hook中的大型函数可以拆分到独立层:
- 数据请求逻辑抽成
service层(比如src/services/card.service.js) - 纯逻辑(验证、解析、计算)用上面的工具函数
- Hook只负责管理状态、协调业务流程(输入变化→验证→请求→解析→更新状态)
优化后的useCard Hook示例
// src/hooks/useCard.js import { useState, useCallback } from 'react'; import { validateCardNumber, parseCardXmlResponse } from '../utils/card.utils'; import { fetchCardData } from '../services/card.service'; export function useCard() { const [cardNumber, setCardNumber] = useState(''); const [error, setError] = useState(''); const [cardData, setCardData] = useState(null); const [isLoading, setIsLoading] = useState(false); const handleInputChange = useCallback((value) => { setCardNumber(value); setError(''); // 输入变化时清空错误提示 }, []); const submitCard = useCallback(async () => { setIsLoading(true); setError(''); try { // 调用独立验证函数 if (!validateCardNumber(cardNumber)) { setError('卡号格式无效,请输入16位数字'); return; } // 调用独立请求函数 const xmlResponse = await fetchCardData(cardNumber); // 调用XML解析工具 const parsedData = parseCardXmlResponse(xmlResponse); setCardData(parsedData); } catch (err) { setError('获取卡片数据失败,请稍后重试'); } finally { setIsLoading(false); } }, [cardNumber]); return { cardNumber, error, cardData, isLoading, handleInputChange, submitCard }; }
3. 解决props传递冗余问题
当父组件需要向子组件传递大量状态和方法时,有两种简洁方案:
方案一:用Context封装状态与操作
创建CardContext和CardProvider,把卡片相关的状态和方法封装在Context中,子组件直接通过useContext获取,无需逐层传递props:
// src/contexts/CardContext.js import { createContext, useContext } from 'react'; import { useCard } from '../hooks/useCard'; const CardContext = createContext(); export function CardProvider({ children }) { const cardState = useCard(); return ( <CardContext.Provider value={cardState}> {children} </CardContext.Provider> ); } export function useCardContext() { return useContext(CardContext); }
然后在CardInput组件中直接使用:
// src/components/CardInput.js import { useCardContext } from '../contexts/CardContext'; export function CardInput() { const { cardNumber, error, isLoading, handleInputChange, submitCard, cardData } = useCardContext(); return ( <div className="card-input-wrapper"> <input type="text" value={cardNumber} onChange={(e) => handleInputChange(e.target.value)} placeholder="请输入16位卡号" disabled={isLoading} /> <button onClick={submitCard} disabled={isLoading || !cardNumber}> {isLoading ? '查询中...' : '查询卡片'} </button> {error && <p className="error-text">{error}</p>} {cardData && ( <div className="card-info"> <p>卡号:{cardData.cardNumber}</p> <p>余额:{cardData.cardBalance}</p> <p>参考价格:{cardData.price}</p> </div> )} </div> ); }
父组件只需用CardProvider包裹即可:
// src/App.js import { CardProvider } from './contexts/CardContext'; import { CardInput } from './components/CardInput'; function App() { return ( <CardProvider> <CardInput /> </CardProvider> ); }
方案二:组件内聚逻辑
如果卡片输入组件是独立模块,直接在CardInput内部使用useCard Hook,把状态和逻辑封装在组件内部,父组件无需传递任何props,直接使用<CardInput />即可。
内容的提问来源于stack exchange,提问作者Djakarta_zero
相关产品推荐
相关产品推荐

