让 React + Typescript 代码更整洁的七个技巧

浏览到这篇文章,再结合着平时开发时遇见的一些问题,觉得写得比较实用。新的一年,就从翻译这篇文章开始。自己总结的同时也方便大家写出更好的代码。部分地方除了翻译外,还加上了些自己的理解与想法。

https://dev.to/ruppysuppy/7-tips-for-clean-react-typescript-code-you-must-know-2da2

前言

干净的代码并不是指能运行的代码。它指的是 代码整洁容易阅读方便理解 以及 易于维护

让我们来看一下 React 整洁代码的最佳实践。它能让我们写的代码维护起来更加容易。

1. 为所有的值提供显式类型

在使用 TypeScript 时,很多人都忽略了给对应的值显式类型。也因此 Get 不到 TypeScript 真正带来的好处。比如在组件中写这样的代码:

错误示例1

const Component = ({ children }: any) => {
  // ...
};

错误示例2

const Component = ({ children }: object) => {
  // ...
};

相反,使用正确的类型定义,能让我们使用起来更轻松,编辑器也会给我们更多的提示。

正确示例

import { FC, ReactNode } from "react";

interface ComponentProps {
  children: ReactNode;
  name: string;
}

const Component:FC<ComponentProps> = (props) => {
  const { name, children, ...rest } = props;
  // ...
};

2. 在更新的方法中使用之前的 state

如果更新的状态要依赖于前一个 State,那么推荐使用函数的方式。React 的更新的批处理的,不以这种方式可能会导致意想不到的结果。

错误示例

import React, { useState } from "react";

export const App = () => {
  const [isDisabled, setIsDisabled] = useState(false);

  const toggleButton = () => {
    setIsDisabled(!isDisabled);
  };

  // here toggling twice will yeild the same result as toggling once
  const toggleButtonTwice = () => {
    toggleButton();
    toggleButton();
  };

  return (
    <div>
      <button disabled={isDisabled}>
        I'm {isDisabled ? "disabled" : "enabled"}
      </button>
      <button onClick={toggleButton}>
        Toggle button state
      </button>
      <button onClick={toggleButtonTwice}>
        Toggle button state 2 times
      </button>
    </div>
  );
};

正确示例

import React, { useState } from "react";

export const App = () => {
  const [isDisabled, setIsDisabled] = useState(false);

  const toggleButton = () => {
    // 使用函数的方式。这里如果使用了 useCallback,也不用将 isDisabled 作为依赖传入
    setIsDisabled((isDisabled) => !isDisabled);
  };

  const toggleButtonTwice = () => {
    toggleButton();
    toggleButton();
  };

  return (
    <div>
      <button disabled={isDisabled}>
        I'm {isDisabled ? "disabled" : "enabled"}
      </button>
      <button onClick={toggleButton}>
        Toggle button state
      </button>
      <button onClick={toggleButtonTwice}>
        Toggle button state 2 times
      </button>
    </div>
  );
};

3. 让单个文件更加干净整洁

将一个页面的不同内容提取为不同的组件。保持文件的原子性和精简性,可以使调试、维护甚至查找文件变得更加容易。

错误示例

// src/App.tsx
export default function App() {
  const posts = [
    {
      id: 1,
      title: "How to write clean react code",
    },
    {
      id: 2,
      title: "Eat, sleep, code, repeat",
    },
  ];

  return (
    <main>
      <nav>
        <h1>App</h1>
      </nav>
      <ul>
        {posts.map((post) => (
          <li key={post.id}>
            {post.title}
          </li>
        ))}
      </ul>
    </main>
  );
}

正确示例

// src/App.tsx
export default function App() {
  return (
    <main>
      <Navigation title="App" />
      <Posts />
    </main>
  );
}

// src/components/Navigation.tsx
interface NavigationProps {
  title: string;
}

export default function Navigation({ title }: NavigationProps) {
  return (
    <nav>
      <h1>{title}</h1>
    </nav>
  );
}

// src/components/Posts.tsx
export default function Posts() {
  const posts = [
    {
      id: 1,
      title: "How to write clean react code",
    },
    {
      id: 2,
      title: "Eat, sleep, code, repeat",
    },
  ];

  return (
    <ul>
      {posts.map((post) => (
        <Post key={post.id} title={post.title} />
      ))}
    </ul>
  );
}

// src/components/Post.tsx
interface PostProps {
  title: string;
}

export default function Post({ title }: PostProps) {
  // 这里只是伪代码。真实的项目中,这里应该还会有很多节点和样式
  return <li>{title}</li>;
}

4. 使用 enum 或者 const 的方式来配置一个变量的多个值

一个变量可能会使用多个不同的值,然后在其它方法中根据不同的值做不同的操作。将这些值使用 enum 或者 const 的方式来配置。后面如果要修改,可以统一修改,并且查找起来也会更加方便。

错误示例

import React, { useState } from "react";

export const App = () => {
  const [status, setStatus] = useState("Pending");

  return (
    <div>
      <p>{status}</p>
      <button onClick={() => setStatus("Pending")}>
        Pending
      </button>
      <button onClick={() => setStatus("Success")}>
        Success
      </button>
      <button onClick={() => setStatus("Error")}>
        Error
      </button>
    </div>
  );
};

正确示例

import React, { useState } from "react";

enum Status {
  Pending = "Pending",
  Success = "Success",
  Error = "Error",
}
// 或者
// const Status = {
//   Pending: "Pending",
//   Success: "Success",
//   Error: "Error",
// } as const;

export const App = () => {
  // use keys as types (both enum and const available)
  const [status, setStatus] = useState<keyof typeof Status>(Status.Pending);
  // use values as types (only enum available)
  // const [status, setStatus] = useState<typeof Status[keyof typeof Status]>(Status.Pending);
  

  return (
    <div>
      <p>{status}</p>
      <button onClick={() => setStatus(Status.Pending)}>
        Pending
      </button>
      <button onClick={() => setStatus(Status.Success)}>
        Success
      </button>
      <button onClick={() => setStatus(Status.Error)}>
        Error
      </button>
    </div>
  );
};

5. 单独定义事件的方法

给一个事件或者方法定义一个单独的函数名,可以更加方便地知道我们要做什么事。并且如果是一个组件的回调方法,使用 useCallback 包裹也会减少组件的 rerender

错误示例

const App = () => {
  return (
    <div>
      <button
        onClick={() => {
          // ...
        }}
      >
        Toggle Dark Mode
      </button>
    </div>
  );
};

正确示例

const App = () => {
  const handleDarkModeToggle = () => {
    // ...
  };

  return (
    <div>
      <button onClick={handleDarkModeToggle}>
        Toggle Dark Mode
      </button>
    </div>
  );
};

6. 优雅地有条件渲染元素

React 中,根据条件来渲染节点非常常见。因此,使用更加整洁的方式来写也非常必要。

错误示例

const App = () => {
  const [isTextShown, setIsTextShown] = useState(false);

  const handleToggleText = () => {
    setIsTextShown((isTextShown) => !isTextShown);
  };

  return (
    <div>
      {isTextShown ? <p>Now You See Me</p> : null}

      {isTextShown && <p>`isTextShown` is true</p>}
      {!isTextShown && <p>`isTextShown` is false</p>}

      <button onClick={handleToggleText}>Toggle</button>
    </div>
  );
};

正确示例

const App = () => {
  const [isTextShown, setIsTextShown] = useState(false);

  const handleToggleText = () => {
    setIsTextShown((isTextShown) => !isTextShown);
  };

  return (
    <div>
      {isTextShown && <p>Now You See Me</p>}

      {isTextShown ? (
        <p>`isTextShown` is true</p>
      ) : (
        <p>`isTextShown` is false</p>
      )}

      <button onClick={handleToggleText}>Toggle</button>
    </div>
  );
};

7. 使用 JSX 简写

Boolean 类型的 Props 值

如果一个 组件的 Props 的值为 true,那么可以省略 ={true}

错误示例

interface TextFieldProps {
  fullWidth: boolean;
}

const TextField = ({ fullWidth }: TextFieldProps) => {
  // ...
};

const App = () => {
  return <TextField fullWidth={true} />;
};

正确示例

interface TextFieldProps {
  fullWidth: boolean;
}

const TextField = ({ fullWidth }: TextFieldProps) => {
  // ...
};

const App = () => {
  return <TextField fullWidth />;
};

String 类型的 Props 值

String 类型的值可以直接使用单引号或者双引号括起来就行,不用再用花括号包裹。花括号是用来包裹变量的。

错误示例

interface AvatarProps {
  username: string;
}

const Avatar = ({ username }: AvatarProps) => {
  // ...
};

const Profile = () => {
  return <Avatar username={"John Wick"} />;
};

正确示例

interface AvatarProps {
  username: string;
}

const Avatar = ({ username }: AvatarProps) => {
  // ...
};

const Profile = () => {
  return <Avatar username="John Wick" />;
};

Undefined 类型的 Props 值

就像 TypeScript 或者 JavaScript 的基础类型一样。如果一个 prop 没有写,那么它的值就是 undefined

错误示例

interface AvatarProps {
  username?: string;
}

const Avatar = ({ username }: AvatarProps) => {
  // ...
};

const Profile = () => {
  return <Avatar username={undefined} />;
};

正确示例

interface AvatarProps {
  username?: string;
  // OR `username: string | undefined`
}

const Avatar = ({ username }: AvatarProps) => {
  // ...
};

const Profile = () => {
  return <Avatar />;
};



原文始发于微信公众号(前端学习总结):让 React + Typescript 代码更整洁的七个技巧

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/83080.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!