能跑的代码并不意味着就是干净的代码。干净的代码指的是组织整齐、易于阅读、易于理解且易于维护的代码。

今天我们要介绍的是如何在React中实现干净代码的7个技巧,以便我们可以轻松地维护代码!

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

在使用TypeScript时,很多人常常会忽略提供显式类型的过程,从而错过了TypeScript所能提供的强大特性。代码库中经常可以看到这样的代码:

错误示例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);
    };

    // 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 = () => {
        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. 尽量使用无TS的TSX

TSX怎么可能无TS?

别急,我们讨论的仅是标记部分而不是整个组件。自由定义函数可以使组件更易于理解。

错误示例:

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>
    );
};

注意:如果你的程序逻辑可以用单行代码完成,那么在TSX中使用是完全可以接受的。

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简写

布尔值Props

truthy prop可以提供给只有prop名称而没有像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 />;
};

字符串Props

String Prop值可以写在双引号中,而无需使用花括号或反引号。

错误示例:

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" />;
};

未定义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 />;
};

现在你应该知道如何编写干净的TSX了吧!

文章目录