优化React代码编写:命令和查询原则的实践指南

前言

在React开发中,编写高质量的代码是至关重要的。优化React代码的编写可以提高代码的可读性、可维护性和扩展性,从而使我们的应用更加健壮和高效。本文将介绍一些命令和查询原则,这些原则可以帮助我们改进React代码的编写。

命令原则是一系列的最佳实践,旨在提供清晰、可维护的代码结构。首先,我们应该使用有意义的变量和函数命名,这样其他开发人员可以轻松理解代码的功能。此外,拆分组件是一种常用的优化方法,它将大型组件拆分为更小的可重用组件,使代码更易于理解和维护。

函数组件和React Hooks是现代React开发中的关键概念。函数组件比类组件更简洁,易于理解和测试。React Hooks提供了一种方便的方式来管理组件的状态和副作用。我们将探索如何使用useState、useEffect和其他React Hooks来提高代码的可读性和可维护性。

另一个重要的原则是避免过多的依赖。只引入需要的依赖,避免引入过多的第三方库或组件,可以减少应用的复杂性和性能开销。此外,我们还将学习如何使用合适的事件处理函数,将事件处理逻辑与组件逻辑分离,以提高代码的可读性。

条件渲染是React中常用的一种技术,它允许我们根据不同的条件来渲染不同的组件或元素。我们将研究如何使用条件语句来实现条件渲染,并避免不必要的组件重新渲染。

除了命令原则,查询原则也是提高React代码编写的关键。我们将探索如何利用官方文档、社区资源和开发者讨论来获取有关React的最新信息和最佳实践。此外,查看React源代码和参考优秀项目也是提高我们代码质量的重要途径。

通过遵循这些命令和查询原则,我们可以不断改进React代码的编写,提高代码质量和开发效率。在接下来的文章中,我们将深入探讨这些原则,并通过实际示例来展示如何应用它们来优化我们的React应用程序。让我们一起开始这个令人兴奋的旅程吧!

实践性

命令与查询分离原则是一种软件设计原则,建议方法或函数要么是修改系统状态的命令,要么是返回系统状态信息的查询,但不能同时兼具两者。

命令(或修饰符)是执行操作或改变对象状态而不返回值的方法。而查询则是读取对象状态而不进行任何更改的方法。将命令和查询分离可以减少组件之间的耦合,使得测试、维护和修改代码更加容易。它还可以更容易地推理代码的行为,并改善系统的整体设计。

以下代码被认为是不好的,因为 addItemremoveItem 做了多个事情:改变数据、更新总价并返回更新后的值。

jsx 复制代码
class ShoppingCart {
  constructor() {
    this.items = [];
    this.totalPrice = 0;
  }

  addItem(item) {
    this.items.push(item);
    this.updateTotalPrice();
    
    return this.totalPrice;
  }

  removeItem(item) {
    const index = this.items.indexOf(item);
    if (index > -1) {
      this.items.splice(index, 1);
      this.updateTotalPrice();
    }

    return this.totalPrice;
  }

  updateTotalPrice() {
    for (let i = 0; i < items.length; i++) {
      this.totalPrice += items[i].price;
    }
  }
}

一个更好的版本可以是这样的:

jsx 复制代码
class ShoppingCart {
  constructor() {
    this.items = [];
    this.totalPrice = 0;
  }

  addItem(item) {
    this.items.push(item);
  }

  removeItem(item) {
    const index = this.items.findIndex((item) => item.id === id);
    if (index > -1) {
      this.items.splice(index, 1);
    }
  }

  get totalPrice () {
      this.items.reduce((total, item) => total + item.price, 0) 
  }
}

请注意,我们将 totalPrice 作为一个getter(查询函数)单独分离出来,因此这些函数可以单独使用而不会产生副作用。

在React应用中,我们可以使用像Redux或React Context API这样的状态管理库来分离修改器和查询。这样可以将修改应用状态的逻辑与渲染用户界面的逻辑分开。

要了解有关上下文和其他钩子的更多信息,您可以在此处下载一份备忘单,其中包含了最常见的React钩子以及示例和插图。

这个命令查询责任分离原则可以应用在不同的层面上。在架构层面上,你可能听说过CQRS。本质上,它们是同样的原则应用在不同的抽象层面上。

购物车

一个购物车应用可能有一个管理购物车商品并计算总价格的类。在该类中, ShoppingCart 方法用于修改购物车商品, addItemremoveItem 方法是修改购物车商品的命令,而 getTotalPrice 方法是返回购物车商品总价格的查询。

在应用命令查询分离原则之前, addItemremoveItem 方法可能会直接更新总价格属性。然而,这样做会使代码更难理解和维护。

这是一个处理购物车的React组件的示例:

jsx 复制代码
import { useState, useMemo } from 'react';

function ShoppingCart() {
  const [cart, setCart] = useState([]);

  // Command: Add item to cart
  function addItemToCart(item) {
    setCart([...cart, item]);
  }

  // Command: Remove item from cart
  function removeItemFromCart(id) {
    setCart(cart.filter((item) => item.id !== id));
  }

  // Query: Calculate total price of items in cart
  const totalPrice = useMemo(() => {
    return cart.reduce((total, item) => total + item.price, 0);
  }, [cart]);

  return (
    <div>
      <h2>Shopping Cart</h2>
      <ul>
        {cart.map((item) => (
          <li key={item.id}>
            {item.name} - {item.price}
            <button onClick={() => removeItemFromCart(item.id)}>Remove</button>
          </li>
        ))}
      </ul>
      <p>Total Price: {totalPrice}</p>
    </div>
  );
}

应用命令查询分离原则后, addItemremoveItem 方法仅修改购物车中的商品,而 getTotalPrice 方法根据购物车中的商品计算总价。

命令查询分离的好处

在你的代码中将命令和查询分开可以带来以下好处:

  • 清晰明了:通过将命令和查询分开,你的代码变得更易读和理解,因为可以更容易地确定每个方法的功能和返回值。
  • 模块化:将命令和查询分离可以使您的代码更具模块性和可重用性,因为命令和查询可以独立使用。
  • 可测试性:将命令和查询分离可以使您的代码更易于测试,因为隔离和测试单个方法更加容易。
  • 简化复杂性:将命令和查询分开可以帮助减少代码的复杂性,因为它鼓励你将复杂的操作拆分成更小、更易管理的部分。

缺点

另一方面,这个原则在代码中引入了一个额外的抽象,这可能会使调试变得更加困难。使用发布-订阅或事件监听机制来分离命令和查询可能会增加调试和理解代码行为的难度,特别是当调用位置与修改的数据相距甚远时。

使用一个明确定义的架构和一致的编码风格对于保持代码的组织性和可维护性至关重要。同样重要的是,使用清晰和描述性的函数和变量名称,以使它们的目的和行为更易于理解。

在React应用程序中,另一种将命令和查询分离的方法是使用像Redux或MobX这样的状态管理库。这些库为应用程序状态提供了一个集中的存储,并提供了一种清晰和结构化的方式来修改和访问来自不同应用程序部分的状态。

在Redux中,我们可以将actions定义为描述状态变化的命令,而reducers则是处理这些actions并返回新状态的查询

jsx 复制代码
// Define actions
const addToCart = (item) => ({
  type: 'ADD_TO_CART',
  payload: item,
});

const removeItemFromCart = (id) => ({
  type: 'REMOVE_FROM_CART',
  payload: id,
});

// Define reducer
const cartReducer = (state = [], action) => {
  switch (action.type) {
    case 'ADD_TO_CART':
      return [...state, action.payload];
    case 'REMOVE_FROM_CART':
      return state.filter((item) => item.id !== action.payload);
    default:
      return state;
  }
};

这样做可以将修改状态的逻辑与渲染用户界面的逻辑分离开来,为应用程序处理状态变化提供了清晰和结构化的方式。

结论

在设计软件时,命令与查询原则是一个重要的考虑因素。将命令和查询分离使得你的代码更加模块化、可测试和易于理解。遵循这个原则,你可以编写更易于维护、更不容易出错和有bug的代码。

总结一下,通过将修改状态的代码与返回状态信息的代码分离,您可以创建更模块化和可测试的代码,这样更易于理解和维护。通过明确命令和查询之间的分离,您可以实现更易于维护和可扩展的软件架构。

相关推荐
半开半落2 分钟前
nuxt3安装pinia报错500[vite-node] [ERR_LOAD_URL]问题解决
前端·javascript·vue.js·nuxt
理想不理想v29 分钟前
vue经典前端面试题
前端·javascript·vue.js
不收藏找不到我30 分钟前
浏览器交互事件汇总
前端·交互
YBN娜44 分钟前
Vue实现登录功能
前端·javascript·vue.js
阳光开朗大男孩 = ̄ω ̄=44 分钟前
CSS——选择器、PxCook软件、盒子模型
前端·javascript·css
minDuck1 小时前
ruoyi-vue集成tianai-captcha验证码
java·前端·vue.js
小政爱学习!1 小时前
封装axios、环境变量、api解耦、解决跨域、全局组件注入
开发语言·前端·javascript
魏大帅。1 小时前
Axios 的 responseType 属性详解及 Blob 与 ArrayBuffer 解析
前端·javascript·ajax
花花鱼1 小时前
vue3 基于element-plus进行的一个可拖动改变导航与内容区域大小的简单方法
前端·javascript·elementui