🌑

使用模块化设计与 ChatGPT 生成代码

Read in English

你可以在这个 codesandbox 中找到本文的所有代码。

很多人没有意识到,如今 AI 真的可以帮助我们写代码!相信我,我一直在使用 chatGPT 帮助我写了数千行代码。让我来告诉你怎么做。
我将以一个前端组件为例,向你展示如何构建一个生产就绪的组件。我们使用 React 来帮助我们模块化代码,这样 chatGPT 就可以更精准地生成代码。
就像人类一样,chatGPT 也不擅长一次处理复杂的事情,所以我们需要为 chatGPT 简化事情。处理系统复杂性的一个强大方法是模块化。我们将从构建最简单的组件开始,然后将它们组合在一起,形成一个页面。为了演示,我这里只做一个简单的 <DialogBox /> 组件。你可以用同样的概念来构建一个大型系统(有些人用它来构建一门新的编程语言)。

需求

第一层:

  1. <DialogBox />:DialogBox 组件应该能够显示两个用户之间的对话,并带有输入区域。

显然,如果我们只是把上面的需求放入 chatGPT,很可能得不到令人满意的结果。因为我们要构建的模块太大,很难清晰地描述它。所以让我们把它拆分成以下几个部分:

第二层:

  1. <Messages />:消息框应该显示用户的对话列表,左侧是对方的消息,右侧是用户自己的消息。
  2. <TextArea />:TextArea 应该显示占位符来引导用户输入内容,当按下回车键时,它应该调用 sendMessage。

我们把一个大组件拆成了两个组件。现在问题变小了,但对 chatGPT 来说仍然有点多。让我们继续拆分。

第三层:

  1. <MessageBubble />:MessageBubble 组件应该显示用户输入的消息文本,方向为左或右。
  2. <Avatar />:Avatar 组件应该显示用户的头像或其他视觉表示。
  3. <TextArea />:同上。

这些对于 chatGPT 生成代码来说应该足够小了。那么让我们邀请我们的 AI 朋友 chatGPT 来帮助我们完成这些组件。

实现

好的!在真正开始开发之前,我们需要确保 chatGPT 和我们处于相同的上下文中。我们需要声明我们拥有的依赖(为了演示,我们只引入简单的依赖,你可以根据需要添加更多):

chatgpt

如你所见,chatGPT 很乐意帮助我们写代码。让我们开始吧!从第三层(最小的部分)开始到第一层。

第三层:

  1. <TextArea />

让我把需求描述给 chatGPT:

chatgpt

这是 chatGPT 给我返回的内容:

chatgpt

这是代码的效果:

chatgpt

看起来不错,我唯一想改的是让文本区域无法调整大小。这很简单,我就自己来做了。你当然也可以让 chatGPT 来做。

  1. <Avatar />

让我们也完成 avatar 组件:

chatgpt chatgpt

如你所见,它为我生成了非常周到的代码,很多细节是我在需求中没有指定的!但我们可以在不输入任何代码的情况下将代码提升到更高的水平。我们只需告诉 chatGPT 这样做即可。让我来展示一下(这里只是演示如何让 chatGPT 改进代码,一些代码是不必要的哈):

chatgpt

看看这些代码,我觉得它们相当不错!你觉得呢?

chatgpt chatgpt

结果是这样的,

chatgpt
  1. <MessageBubble />
chatgpt

ChatGPT 返回了这个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// MessageBubble.tsx
import React, { FC } from "react";
import styles from "./MessageBubble.module.scss";
import Avatar, { AvatarSize, AvatarType } from "../Avatar";

type Props = {
text: string;
direction: "left" | "right";
imgUrl?: string;
username?: string;
avatarSize?: AvatarSize;
avatarType?: AvatarType;
};

const MessageBubble: FC<Props> = ({
text,
direction,
imgUrl,
username,
avatarSize = "small",
avatarType = "square"
}) => {
return (
<div className={`${styles.messageBubble} ${styles[direction]}`}>
{imgUrl && (
<div className={styles.avatarWrapper}>
<Avatar imgUrl={imgUrl} size={avatarSize} type={avatarType} />
</div>
)}
<div className={styles.contentWrapper}>
{username && <div className={styles.username}>{username}</div>}
<div className={styles.messageText}>{text}</div>
</div>
</div>
);
};

export default MessageBubble;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// MessageBubble.module.scss
.messageBubble {
display: flex;
align-items: center;
.contentWrapper {
display: inline-block;
max-width: 80%;
margin: 0.5rem;
padding: 0.75rem;
border-radius: 1rem;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05), 0 2px 6px 0 rgba(0, 0, 0, 0.05);
background-color: #fff;
}
}
.left {
justify-content: flex-start;
}

.right {
flex-direction: row-reverse;
.username {
display: flex;
justify-content: flex-end;
}
}

.avatarWrapper {
margin-top: 0.5rem;
margin-right: 0.5rem;
}

.username {
font-size: 0.75rem;
font-weight: 600;
color: #999;
margin-bottom: 0.25rem;
}

.messageText {
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #333;
}
chatgpt

结果还不错,除了一些需要适配的样式问题。大部分代码都不需要修改。

第二层:

从第二层开始,我们需要做的是组合 chatGPT 之前构建的组件。让我们告诉 chatGPT 这样做。

  1. <Messages />
chatgpt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Messages.tsx
import { FC } from 'react';
import styles from './Messages.module.scss';
import MessageBubble from '../MessageBubble';
import { Message } from './types';

type Props = {
messages: Message[];
};

const Messages: FC<Props> = ({ messages }) => {
return (
<div className={styles.messagesWrapper}>
{messages.map((message, index) => (
<MessageBubble
key={index}
text={message.text}
direction={message.direction}
imgUrl={message.avatar}
username={message.username}
/>
))}
</div>
);
};

export default Messages;
1
2
3
4
5
6
7
8
// Messages.module.scss
.messagesWrapper {
display: flex;
flex-direction: column;
align-items: flex-start;
margin-top: 1rem;
margin-bottom: 1rem;
}
chatgpt

看起来相当不错~

第一层:

  1. <DialogBox />
chatgpt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// Dialogbox.tsx
import { FC, useState, useEffect } from 'react';
import styles from './DialogBox.module.scss';
import Messages from './Messages';
import TextArea from './TextArea';
import { Message } from './types';

type Props = {
getMessages: () => Promise<Message[]>;
sendMessage: (text: string) => Promise<void>;
};

const DialogBox: FC<Props> = ({ getMessages, sendMessage }) => {
const [messages, setMessages] = useState<Message[]>([]);

useEffect(() => {
const interval = setInterval(() => {
getMessages().then((messages) => setMessages(messages));
}, 1000);
return () => clearInterval(interval);
}, [getMessages]);

const handleSendMessage = async (text: string) => {
await sendMessage(text);
const updatedMessages = await getMessages();
setMessages(updatedMessages);
};

return (
<div className={styles.dialogBox}>
<div className={styles.messagesWrapper}>
<Messages messages={messages} />
</div>
<div className={styles.textAreaWrapper}>
<TextArea sendMessage={handleSendMessage} />
</div>
</div>
);
};

export default DialogBox;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
.dialogBox {
display: flex;
flex-direction: column;
align-items: stretch;
height: 100%;
margin: 1rem;
}

.messagesWrapper {
flex: 1;
}

.textAreaWrapper {
margin-top: 1rem;
}
chatgpt

如你所见,大多数时候我并不在写代码,而是设计组件并告诉 chatGPT 它是什么。ChatGPT 会给我一个相当令人满意的结果。经过简单的代码审查,开发就完成了。关键在于将大问题拆分成小问题,这样我们就可以清楚地描述它们,chatGPT 也更容易理解。我们可以用这种方法来构建一些大型系统,这是完全可行的。

, , , , — Feb 22, 2023