第4部分:编写清洁有效的反应代码 - 最佳实践和优化技术
#javascript #react #cleancode #bestpractices

欢迎参与我们有关“ 2023年 React最佳实践”系列的第4部分!在这一部分中,我们将探讨各种技术和策略,以在您的React应用程序中编写干净有效的代码。通过遵循这些最佳实践,您可以改善可维护性 performance 可读性

让我们潜入并学习如何编写干净有效的反应代码,不仅效果很好,而且更易于理解,维护和扩展。

1.实现错误边界以优雅处理组件错误

将您的组件或应用程序的特定部分包裹在以捕获和处理错误的错误边界以受控方式处理。

这可以防止整个应用程序崩溃,并提供后备UI或错误消息,改善用户体验并使调试问题更容易。

高阶组件(HOC) - witherrorboundary:

// HOC for error boundary
const withErrorBoundary = (WrappedComponent) => {
  return (props) => {
    const [hasError, setHasError] = useState(false);
    const [errorInfo, setErrorInfo] = useState(null);

    useEffect(() => {
      const handleComponentError = (error, errorInfo) => {
        setHasError(true);
        setErrorInfo(errorInfo);
        // You can also log the error to an error reporting service here
      };

      window.addEventListener('error', handleComponentError);

      return () => {
        window.removeEventListener('error', handleComponentError);
      };
    }, []);

    if (hasError) {
      // You can customize the fallback UI or error message here
      return <div>Something went wrong. Please try again later.</div>;
    }

    return <WrappedComponent {...props} />;
  };
};

用法:

// HOC for error boundary
import withErrorBoundary from './withErrorBoundary';

const Todo = () => {
  // Component logic and rendering
}

const WrappedComponent = withErrorBoundary(Todo);

2.使用react.memo用于功能组件

react.memo是一个高阶组件,可以记忆功能组件的结果,防止不必要的重新租赁

通过用react.memo将功能组件包裹起来,您可以通过跳过重新租用器来优化性能,而当组件的道具没有更改

这是一个例子,

// ❌ 
const TodoItem = ({text}) => {
  return <div> {text} </div>
} 

// Todo

const Todo = () => {
 //... Component logic

return <div>
 //.. Other elements
   <TodoItem //.. />
</div>
}

在此示例中,我们有一个称为todoitem的功能组件,该功能组件接收名称prop并呈现todo文本。

默认情况下,每当 todo parent component 重新渲染时,组件将重新渲染。

为了优化性能,我们可以用react.memo将todoitem 包装,创建了组件的回忆版本。这种记忆的组件只有在其道具更改后才会重新渲染

// ✅ Memoized version of TodoItem using React.memo
const TodoItem = React.memo(({text}) => {
  return <div> {text} </div>
}) 

通过使用react.memo,我们可以防止不必要的重新呈现并优化功能组件的性能。

然而,重要的是要注意反应。memo对道具的浅层比较。如果您的组件将复杂的数据结构作为道具接收,请确保您适当处理Prop更新以进行准确的记忆。


3.使用绒布以获得代码质量

使用诸如ESLINT之类的Linter工具可以大大提高您的反应项目代码质量和一致性。

通过使用衬里,您可以:

  • 确保一致的代码样式

  • 捕获错误和有问题的模式

  • 提高代码可读性和可维护性

  • 执行编码标准和约定


4.避免默认导出

默认导出的问题是,它可以使更难理解哪些组件在其他文件中导入和使用。它还限制了导入的灵活性,因为默认导出只能每个文件单默认导出

// ❌ Avoid default export
const Todo = () => {
  // component logic...
};

export default Todo;  

相反,建议在React中使用命名的出口:

// ✅ Use named export
const Todo = () => {

}

export { Todo };

使用命名的导出提供更好的清晰度导入组件时,使代码库更有条理且易于浏览。

  • 命名的导入与摇晃

树木摇动是一个通常在JavaScript上下文中使用的术语,用于描述去除死亡代码。它依赖于导入语句来检测是否将代码模块导出并导入在JavaScript文件之间使用。

  • 重构变得更容易。

  • 更容易识别和了解模块的依赖项


5.使用对象破坏

当我们使用直接属性访问使用点表示法用于访问对象的各个属性时,对于简单的情况就可以正常工作。

// ❌ Avoid direct property access using dot notation
const todo = {
   id: 1,
   name: "Morning Task",
   completed: false
}

const id = todo.id;
const name = todo.name;
const completed = todo.completed;

这种方法在简单的情况下可以很好地工作,但是在处理较大对象时或仅需要属性的子集时,它可能会变得困难和重复 另一方面,

对象破坏为提取对象属性提供了一种更简洁,更优雅的方法。它允许您使用类似于对象文字符号的语法破坏对象,并将多个属性分配给变量。

// ✅ Use object destructuring
const { id, name = "Task", completed } = todo; 
  • 它减少了对重复>对象属性访问的需求。

  • 支持默认值的分配

  • 允许变量重命名混叠


6.使用片段

片段允许在呈现多个元素时避免不必要的包装器div。

// ❌ Avoid unnecessary wrapper div
const Todo = () => (
  <div>
    <h1>Title</h1>
    <ul>
      // ...
    </ul>
  </div>
);

在上面的代码中,不必要的包装器Div可以为DOM结构增加不必要的复杂性,从而可能影响您的网页的可访问性。

// ✅ Use fragments
const Todo = () => (
  <>
    <h1>Title</h1>
    <ul>
      // ...
    </ul>
  </>
);

7.更喜欢通过对象而不是多个道具

当我们使用多个参数或道具用于将与用户相关的信息传递给组件或功能时,记住每个参数的顺序和目的,尤其是当参数的数量时成长。

// ❌ Avoid passing multiple arguments
const updateTodo = (id, name, completed) => {
 //...
}

// ❌ Avoid passing multiple props
const TodoItem = (id, name, completed) => {
  return(
    //...
  )
}

当参数数量增加时,维护和重构代码变得更具挑战性。犯错的机会增加了,例如省略论点提供不正确的值

// ✅ Use object arguments
const updateTodo = (todo) => {
 //...
}

const todo = {
   id: 1,
   name: "Morning Task",
   completed: false
}

updateTodo(todo);
  • 功能变得更加自我描述易于理解

  • 减少不正确的参数顺序引起的错误的机会

  • 易于添加修改 属性而无需更改函数签名。

  • 简化调试的过程测试函数以将对象作为参数传递。


8.使用箭头功能

箭头功能提供了更简洁的语法和词汇范围,消除了对显式this绑定和改善代码可读性的需求。

// ❌
function sum(a, b) {
  return a + b;
}

上面的代码可能会导致详细的代码,并可能导致有关this的上下文和约束的误解。

// ✅ Use arrow function
const sum = (a, b) => a + b;
  • 箭头功能使代码更 compact 表达

  • it 自动绑定上下文,减少了this相关错误的机会。

  • 它改善了代码可维护性


9.使用枚举代替数字或字符串

// ❌ Avoid Using numbers or strings
switch(status) {
  case 1:
    return //...
  case 2:
    return //...
  case 3:
    return //...
}

上面的代码上方很难理解和维护,因为数字的含义可能无法立即清楚。

// ✅ Use Enums
const Status = {
  NOT_STARTED: 1,
  IN_PROGRESS: 2,
  COMPLETED: 3
}

const { NOT_STARTED, IN_PROGRESS COMPLETED } = Status;

switch(status) {
  case NOT_STARTED:
    return //...
  case IN_PROGRESS:
    return //...
  case COMPLETED:
    return //...
}
  • 改进代码可读性

  • 减少 typos 不正确的值的机会

  • 更好的类型检查编辑自动完成文档


10.使用速记进行布尔道具

// ❌
<Dropdown multiSelect={false} />
// ✅ Use shorthand
<Dropdown multiSelect />

布尔道具的速记语法通过减少不必要的杂语并使意图清晰明了。


11.避免将索引用作关键道具

// ❌ Avoid index as key
const renderItem = (todo, index) => {
  const {name} = todo;
  return <li key={index}> {name} </>
}

使用索引作为关键道具可能会导致 *渲染 *,尤其是在添加,删除或重新排序列表项目时。

它可能导致性能不正确的组件更新

// ✅ Using unique and stable identifiers
const renderItem = (todo, index) => {
  const {id, name} = todo;
  return <li key={id}> {name} </>
}
  • 在列表中有效更新和重新排序组件。

  • 减少潜在的渲染问题。

  • 避免校正内部的组件更新。


12.在小功能中使用隐式返回

// ❌ Avoid using explicit returns 
const square = value => {
  return value * value;
}

当我们使用显式返回时,可以使小函数定义不必要的更长,并且更难阅读。

由于附加卷曲括号显式返回语句
可能会导致更多混乱的代码

// ✅ Use implicit return
const square = value => value * value;
  • 隐式返回降低代码的杂语

  • 改进代码可读性

  • 它可以通过关注主逻辑而不是返回语句来增强代码可维护性。


13.使用Proptypes进行类型检查

// ❌ Bad Code
const Button = ({ text, enabled }) => 
      <button enabled>{text}</button>;

上面的代码可能导致通过不正确 Prop类型,这可能导致运行时错误意外行为

// ✅ Use PropTypes
import PropTypes from 'prop-types';

const Button = ({ enabled, text }) => 
      <button enabled> {text} </button>;

Button.propTypes = {
  enabled: PropTypes.bool
  text: PropTypes.string.isRequired,
};
  • 它有助于在编译时间上捕获错误

  • 它提供了更好的理解和组件的预期类型。

  • proptypes充当文档对于使用该组件工作的其他开发人员。


14.更喜欢使用模板文字

// ❌ Bad Code
const title = (seriesName) => 
      "Welcome to " + seriesName + "!";

上面的代码可能会导致冗长代码,并使字符串插值或串联更加困难。

// ✅ Use template literals
const title = (seriesName) => 
      `Welcome to ${seriesName}!`;
  • 它通过允许字符串内的可变插值来简化字符串操纵

  • 它使代码更表达式易于阅读

  • 它支持没有其他解决方法的多行字符串。

  • 改进代码格式。


15.避免巨大的组成部分

避免反应中的巨大组件对于维持清洁,模块化和可维护的代码至关重要。

大型组件往往更复杂,更难理解,并且容易出现问题。让我们探索一个例子来说明这一概念:

// ❌ Avoid huge component
const Todo = () => {
  // State Management
  const [text, setText] = useState("");
  const [todos, setTodos] = useState([])
  //... More states

  // Event Handlers
  const onChangeInput = () => //...
  // Other event handlers

  return (
   <div>
      <input //.. />
      <input //.. />   
      <button //.. />
      <list //... >
        <list-item //..>
      </list/>
   </div>
  )
};

export default Todo;  

在上面的示例中,我们有一个称为Todo的组件,其中包含多个状态变量事件处理程序元素

随着组件的增长,它变得更难管理, debug 理解

您可以检查下面的博客以解决此问题,建议将如此巨大的组件分解为较小可重复使用集中的组件


请继续关注即将推出的博客,该博客专门针对React 中的优化技术。我们将探索其他策略,以提高组件的性能和效率。不要错过这些宝贵的见解!

快乐的编码!