7個技巧讓你寫出乾淨的 TSX 程式碼

原文鏈接://dev.to/ruppysuppy/7-tips-for-clean-react-typescript-code-you-must-know-2da2

「乾淨的程式碼」不僅是可以正常運行的程式碼。它指的是組織整齊易於閱讀易於理解且易於維護的程式碼。

讓我們來看看 React 中「乾淨程式碼」的一些最佳實踐,它們可以讓你更加輕鬆地維護程式碼!🚀🌕

1. 為所有值提供顯式類型

使用 TypeScript 時,很多人經常不為值提供顯式類型,從而錯失 TS 在開發中的真正用處

壞栗子 01:

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

壞栗子 02:

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

恰當地使用interface 能夠讓編輯器給你提供準確的提示,從而讓敲程式碼變得更容易

好栗子:

import { ReactNode } from "react";

interface ComponentProps {
  children: ReactNode;
}

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

2. 更新狀態時考慮先前的狀態

如果更新狀態時新狀態依賴於舊狀態,在調用更新狀態函數時傳入函數來更新狀態,React 狀態更新會進行批處理,如果不使用這種方式更新狀態很可能導致意想不到的結果

壞栗子:

import React, { useState } from "react";

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

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

  // 此處調用兩次toggleButton的結果和調用一次相同
  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 = () => {
    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. 對具有多個狀態的值使用枚舉或常量對象

使用枚舉或常量對象可以大大簡化管理存在多種狀態的變數的過程

壞栗子:

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",
}
// OR
// const Status = {
//   Pending: "Pending",
//   Success: "Success",
//   Error: "Error",
// } as const;

export const App = () => {
  const [status, setStatus] = useState(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. 盡量不在視圖中編寫邏輯

盡量不要把邏輯程式碼嵌入到標籤中

壞栗子:

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. 正確地選擇條件渲染的方式

正確地選擇條件渲染的方式可以讓程式碼更優雅

壞栗子:

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簡寫

布爾屬性

一個具有真值的屬性可以只寫屬性名,比如truthyProp,而不必寫成truthyProp={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 />;
};

字元串屬性

屬性值為字元串字面量可以直接用雙引號包裹

壞栗子:

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 屬性

和普通的TS/JS一樣,如果屬性未提供值,則為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 />;
};

現在你應該知道怎麼編寫乾淨的 TSX 了

完結!撒花!

w8sw6yese1i6w3sxcm4t

公眾號【今天也要寫bug】(op-bot)提問答疑