You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 05:36:13