首页 > web前端 > js教程 > 重构 React:驯服混乱,一次一个组件

重构 React:驯服混乱,一次一个组件

Mary-Kate Olsen
发布: 2025-01-15 07:35:43
原创
484 人浏览过

Refactoring React: Taming Chaos, One Component at a Time

重构 React 代码就像把一个混乱的厨房变成一个组织良好的烹饪天堂。它是关于在不改变应用程序功能的情况下改进应用程序的结构、可维护性和性能。无论您是在与臃肿的组件还是混乱的状态逻辑作斗争,精心策划的重构都会将您的代码库转变为流畅、高效的机器。

本博客揭示了常见的重构场景,提供了可行的解决方案,并使您能够释放 React 应用程序的真正潜力。


我。什么是重构以及为什么它很重要?

重构可以在不改变代码功能的情况下改进代码的结构。这不是为了修复错误或添加功能,而是为了让您的代码对人类和机器都更好。

为什么要重构?

  1. 可读性:当代码读起来像一本好小说而不是一个神秘的谜题时,在凌晨 3 点调试代码会变得容易得多。
  2. 可维护性:干净的代码库可以节省数小时的入门时间并加快更新速度。
  3. 性能:更简洁的代码通常意味着更快的加载时间和更流畅的用户体验。

专业提示:避免过早优化。当有明确的需求时进行重构,例如改善开发人员体验或解决缓慢的渲染问题。


二.嗅出代码味道

代码异味是低效率或复杂性的微妙信号。它们不是错误,但它们表明了需要改进的地方。

常见的 React 代码味道

  1. 臃肿的组件
    • 问题:单个组件处理太多职责,例如获取数据、渲染和处理事件。
   function ProductPage() {
     const [data, setData] = useState([]);
     useEffect(() => fetchData(), []);
     const handleAddToCart = () => { ... };
     return (
       <div>
         {data.map(item => <ProductItem key={item.id} item={item} />)}
         <button onClick={handleAddToCart}>Add to Cart</button>
       </div>
     );
   }
登录后复制
登录后复制
  • 解决方案: 将其分解为更小的、更集中的组件。
   function ProductPage() {
     return (
       <div>
         <ProductList />
         <CartButton />
       </div>
     );
   }

   function ProductList() {
     const [data, setData] = useState([]);
     useEffect(() => fetchData(), []);
     return data.map(item => <ProductItem key={item.id} item={item} />);
   }

   function CartButton() {
     const handleAddToCart = () => { ... };
     return <button onClick={handleAddToCart}>Add to Cart</button>;
   }
登录后复制
登录后复制
  1. 支柱钻井
    • 问题: 通过多层组件传递 props。
   <App>
     <ProductList product={product} />
   </App>
登录后复制
登录后复制
  • 解决方案1:使用组合。
   <ProductList>
     <ProductItem product={product} />
   </ProductList>
登录后复制
登录后复制
  • 解决方案 2: 使用上下文。
   const ProductContext = React.createContext();

   function App() {
     const [product, setProduct] = useState({ id: 1, name: 'Example Product' }); // Example state
     return (
       <ProductContext.Provider value={product}>
         <ProductList />
       </ProductContext.Provider>
     );
   }

   function ProductList() {
     const product = useContext(ProductContext);
     return <ProductItem product={product} />;
   }
登录后复制
  1. 嵌套三元地狱
    • 问题: 使用嵌套三元组的复杂条件渲染。
   return condition1 ? a : condition2 ? b : condition3 ? c : d;
登录后复制
  • 解决方案: 使用辅助函数或 switch 语句进行重构。
   function renderContent(condition) {
     switch (condition) {
       case 1: return a;
       case 2: return b;
       case 3: return c;
       default: return d;
     }
   }

   return renderContent(condition);
登录后复制
  1. 重复逻辑
    • 问题:跨组件重复相同的逻辑。
   function calculateTotal(cart) {
     return cart.reduce((total, item) => total + item.price, 0);
   }
登录后复制
  • 解决方案: 将共享逻辑移至可重用实用程序或自定义挂钩中。
   function calculateTotalPrice(cart) {
     return cart.reduce((total, item) => total + item.price, 0);
   }

   function useTotalPrice(cart) {
     return useMemo(() => calculateTotalPrice(cart), [cart]);
   }
登录后复制
  1. 过度状态
    • 问题:直接管理派生状态。
   const [isLoggedIn, setIsLoggedIn] = useState(user !== null);
登录后复制
  • 解决方案: 使用派生状态代替。
   const isLoggedIn = !!user; // Converts 'user' to boolean
登录后复制

三.简化状态管理

状态管理很重要,但很快就会变得混乱。以下是简化方法:

派生状态:计算,不存储

  • 问题:存储冗余状态。
  • 解决方案:直接从源计算派生值。
  const [cartItems, setCartItems] = useState([]);
  const totalPrice = cartItems.reduce((total, item) => total + item.price, 0);
登录后复制

使用 useReducer 处理复杂状态

  • 问题:多个相互依赖的状态。
  • 解决方案:使用useReducer。
  const initialState = { count: 0 };
  function reducer(state, action) {
    switch (action.type) {
      case 'increment': return { count: state.count + 1 };
      default: return state;
    }
  }
  const [state, dispatch] = useReducer(reducer, initialState);
登录后复制

状态托管

  • 问题:用于本地数据的全局状态。
  • 解决方案:将状态移近需要的位置。
  // Before:
  function App() {
    const [filter, setFilter] = useState('');
    return <ProductList filter={filter} onFilterChange={setFilter} />;
  }

  // After:
  function ProductList() {
    const [filter, setFilter] = useState('');
    return <FilterInput value={filter} onChange={setFilter} />;
  }
登录后复制

四。重构组件

组件应该只做一项工作并且做得很好。例如:

每个组件一个作业

function MemberCard({ member }) {
  return (
    <div>
      <Summary member={member} />
      <SeeMore details={member.details} />
    </div>
  );
}
登录后复制

V.性能优化

反应分析器

使用分析器来识别瓶颈。在“Profiler”下的开发者工具中访问它。

记忆

优化昂贵的计算:

   function ProductPage() {
     const [data, setData] = useState([]);
     useEffect(() => fetchData(), []);
     const handleAddToCart = () => { ... };
     return (
       <div>
         {data.map(item => <ProductItem key={item.id} item={item} />)}
         <button onClick={handleAddToCart}>Add to Cart</button>
       </div>
     );
   }
登录后复制
登录后复制

注意:避免过度使用频繁更新的依赖项的记忆。


六。重构可测试性

编写以用户为中心的测试:

   function ProductPage() {
     return (
       <div>
         <ProductList />
         <CartButton />
       </div>
     );
   }

   function ProductList() {
     const [data, setData] = useState([]);
     useEffect(() => fetchData(), []);
     return data.map(item => <ProductItem key={item.id} item={item} />);
   }

   function CartButton() {
     const handleAddToCart = () => { ... };
     return <button onClick={handleAddToCart}>Add to Cart</button>;
   }
登录后复制
登录后复制

七。可维护性的最后润色

  1. 按功能组织:
   <App>
     <ProductList product={product} />
   </App>
登录后复制
登录后复制
  1. 使用绝对导入:
   <ProductList>
     <ProductItem product={product} />
   </ProductList>
登录后复制
登录后复制

八。备忘单

Category Tip
Code Smells Split bloated components; avoid prop drilling.
State Management Use derived state; colocate state.
Performance Use Profiler; optimize Context values.
Testing Test behavior, not implementation details.
类别
提示 标题> 代码味道 拆分臃肿的组件;避免支柱钻孔。 状态管理 使用派生状态;并置状态。 性能 使用分析器;优化上下文值。 测试 测试行为,而不是实现细节。 表>

以上是重构 React:驯服混乱,一次一个组件的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:dev.to
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板