React 和 TypeScript中 常见的代码优化建议

  1. 使用函数式组件:函数式组件是 React 中推荐的编写组件的方式,相对于类组件,它们具有更轻量的语法和更好的性能表现。

  2. 使用 React.memo 进行组件的浅比较优化:使用 React.memo 可以包裹组件,在传入的 props 发生变化时,进行浅比较,避免不必要的重渲染。

import React from 'react';

interface Props {
  name: string;
}

const MyComponent: React.FC<Props> = React.memo(({ name }) => {
  return <div>{name}</div>;
});
  1. 使用 useCallback 优化回调函数:使用 useCallback 来对回调函数进行缓存,以确保在父组件重新渲染时,回调函数的引用保持不变,避免不必要的子组件重渲染。
import React, { useCallback } from 'react';

interface Props {
  onClick: () => void;
}

const MyButton: React.FC<Props> = ({ onClick }) => {
  const handleClick = useCallback(() => {
    onClick();
  }, [onClick]);

  return <button onClick={handleClick}>Click Me</button>;
};
  1. 使用 useMemo 优化计算结果:使用 useMemo 来对计算结果进行缓存,以避免在每次渲染时都重新计算相同的结果。
import React, { useMemo } from 'react';

interface Props {
  a: number;
  b: number;
}

const MyComponent: React.FC<Props> = ({ a, b }) => {
  const sum = useMemo(() => {
    console.log('Calculating sum');
    return a + b;
  }, [a, b]);

  return <div>{sum}</div>;
};
  1. 避免在 render 方法中定义新对象:在 render 方法中定义新的对象,会导致在每次重新渲染时都创建新的对象实例,建议将对象定义在 render 方法外部。
import React from 'react';

interface Props {
  data: number[];
}

const MyComponent: React.FC<Props> = ({ data }) => {
  const mappedData = data.map((item) => item * 2);

  return (
    <div>
      {mappedData.map((item) => (
        <span key={item}>{item}</span>
      ))}
    </div>
  );
};
  1. 类型推断和类型声明:合理利用 TypeScript 的类型推断和类型声明,增加代码的可读性和可维护性,避免潜在的类型错误。
7. 类型推断:
const name = 'John'; // TypeScript会自动推断name的类型为string
const age = 25; // TypeScript会自动推断age的类型为number
function multiply(a: number, b: number) {
  return a * b;
}
const result = multiply(5, 10); // TypeScript会自动推断result的类型为number

8. 类型声明:
interface Person {
  name: string;
  age: number;
}
function greet(person: Person) {
  console.log(`Hello, ${person.name}! You are ${person.age} years old.`);
}
const john: Person = { // 使用类型声明明确john的类型为Person
  name: 'John',
  age: 25,
};
greet(john);

9. 类型推断和类型声明结合使用:
function add(a: number, b: number): number {
  return a + b;
}
const result = add(5, 10); // TypeScript根据add函数的返回类型声明result的类型为number
const user = {
  name: 'John',
  age: 25,
};
type User = typeof user; // 使用typeof关键字将user对象的类型推断为User类型
const newUser: User = {
  name: 'Jane',
  age: 30,
};
  1. 使用 interface 或 type 声明组件 props 和状态:使用接口(interface)或类型(type)来明确定义组件的 props 和状态的类型,提高代码的可读性和可维护性。
1. 使用接口定义组件的props类型:
interface ButtonProps {
  onClick: () => void;
  disabled?: boolean;
  label: string;
}
const Button: React.FC<ButtonProps> = ({ onClick, disabled, label }) => {
  return (
    <button onClick={onClick} disabled={disabled}>
      {label}
    </button>
  );
};

2. 使用类型别名定义组件的props类型:
type ButtonProps = {
  onClick: () => void;
  disabled?: boolean;
  label: string;
};
const Button: React.FC<ButtonProps> = ({ onClick, disabled, label }) => {
  return (
    <button onClick={onClick} disabled={disabled}>
      {label}
    </button>
  );
};

3.使用接口定义组件的状态类型:
interface CounterState {
  count: number;
  step: number;
}

class Counter extends React.Component<{}, CounterState> {
  state: CounterState = {
    count: 0,
    step: 1,
  };
  render() {
    const { count, step } = this.state;
    return (
      <div>
        <p>Count: {count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
  increment = () => {
    this.setState((prevState) => ({
      count: prevState.count + this.state.step,
    }));
  };
}
4. 使用类型别名定义组件的状态类型:
type CounterState = {
  count: number;
  step: number;
};

class Counter extends React.Component<{}, CounterState> {
  state: CounterState = {
    count: 0,
    step: 1,
  };

  render() {
    const { count, step } = this.state;
    return (
      <div>
        <p>Count: {count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }

  increment = () => {
    this.setState((prevState) => ({
      count: prevState.count + this.state.step,
    }));
  };
}
 
  1. 使用枚举类型:使用 TypeScript 的枚举类型来增加代码的可读性,避免魔法数字。
enum Direction {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT',
}

function move(direction: Direction): void {
  if (direction === Direction.Up) {
    console.log('Moving up');
  } else if (direction === Direction.Down) {
    console.log('Moving down');
  } else if (direction === Direction.Left) {
    console.log('Moving left');
  } else if (direction === Direction.Right) {
    console.log('Moving right');
  }
}

move(Direction.Up); // 输出:Moving up
move(Direction.Left); // 输出:Moving left
使用魔法数字的弊端:
1.可读性差:直接在代码中使用数字,特别是没有注释或解释的情况下,会使代码变得难以理解和维护。其他开发人员阅读代码时可能无法立即理解数字的含义和目的。
2.可维护性差:当需要修改代码时,如果魔法数字散布在整个代码库中,就需要逐个查找并修改每个实例。这增加了出错的风险,并且容易遗漏或忽略一些实例。
3.难于调试:如果出现错误或需要调试代码时,使用魔法数字会使问题的定位和排查变得困难。调试器和日志消息通常不会提供有关具体数字的上下文信息。
4.可复用性差:如果将来需要在其他地方使用相同的值,或者需要根据需求进行调整,重新使用魔法数字的代码会变得困难并且容易引入错误。
  1. 使用可选链操作符(Optional Chaining):通过使用可选链操作符(?.)来访问可能为空的属性或方法,在代码中减少了一些不必要的空值判断。
可选链操作符(Optional Chaining)的规则如下:
1.对象属性的可选链操作:使用?.来访问对象的属性。如果属性存在且不为nullundefined,表达式将继续求值;如果属性不存在或为nullundefined,表达式将立即返回undefinedconst obj = {
  prop1: {
    prop2: {
      prop3: 'value',
    },
  },
};
console.log(obj.prop1?.prop2?.prop3); // 输出:'value'
console.log(obj.prop1?.prop2?.prop4); // 输出:undefined

2. 函数调用的可选链操作:使用?.来调用可能为nullundefined的函数。如果函数存在且不为nullundefined,调用将正常执行;如果函数不存在或为nullundefined,调用将不会引发错误,而是立即返回undefinedconst obj = {
  func: () => 'Hello',
};
console.log(obj.func?.()); // 输出:'Hello'
console.log(obj.unknownFunc?.()); // 输出:undefined

注意:可选链操作符在部分浏览器和环境中可能还不被完全支持,请根据目标环境进行兼容性考虑或使用工具进行转译。

  1. 合理拆分和组织组件:将大型组件拆分为更小的组件,提高代码的可维护性和重用性。同时,通过合理组织组件的文件结构,使代码更易于理解和维护。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值