weather-app开发手记 04 AntDesign组件库使用解析 | 项目设计困惑

Ant Design of React - Ant Design

1 城市搜索CitySearch组件的UI

TypeScript 复制代码
import React, { useState } from "react";
import { Select, Button, Space, message } from "antd";
import { SearchOutlined } from "@ant-design/icons";
import { CITIES } from "../../../utils/constants";
import { useWeatherStore } from "@/stores/weatherStore";

const CitySearch: React.FC = () => {
  const [selectedCity, setSelectedCity] = useState<string>("北京");
  const { fetchWeather, loading } = useWeatherStore();

  // 获取城市列表
  const cityOptions = Object.keys(CITIES).map((city) => ({
    label: city,
    value: city,
  }));

  // 城市选择处理逻辑
  const handleSearch = async () => {
    if (!selectedCity) {
      message.warning("请选择城市");
      return;
    }

    const cityId = CITIES[selectedCity];
    if (!cityId) {
      message.error("城市信息错误");
      return;
    }

    try {
      await fetchWeather({ city: cityId }, selectedCity);
      message.success(`已获取 ${selectedCity} 的天气信息`);
    } catch (error) {
      message.error("获取天气数据失败,请重试");
    }
  };

  return (
    <Space.Compact style={{ width: "100%" }}>
      <Select
        value={selectedCity}
        onChange={setSelectedCity}
        options={cityOptions}
        style={{ flex: 1 }}
        placeholder="选择城市"
        size="large"
      />
      <Button
        type="primary"
        size="large"
        icon={<SearchOutlined />}
        onClick={handleSearch}
        loading={loading}
      >
        查询
      </Button>
    </Space.Compact>
  );
};

export default CitySearch;

1.分析代码中如何使用

TypeScript 复制代码
import { Select, Button, Space, message } from "antd";
import { SearchOutlined } from "@ant-design/icons";

在 CitySearch 组件中,可以看到以下 Ant Design 组件的使用:

  • Select - 下拉选择框,用于城市选择
  • Button - 按钮组件,用于触发搜索
  • Space.Compact - 布局组件,让元素紧凑排列
  • message - 全局提示组件,用于用户反馈

2. 为什么使用组件库

开发效率

  • 开箱即用:无需从零开始构建基础组件
  • 功能完整:组件已包含交互逻辑、键盘支持、无障碍访问等特性
  • 统一规范:遵循设计规范,保证界面一致性

质量保证

  • 经过测试:组件库经过大量测试,稳定性高
  • 跨浏览器兼容:解决各种兼容性问题
  • 持续维护:有专业团队维护和更新

3. 使用组件库的好处

代码层面

  • 减少代码量:如你的代码中,Select 组件一行代码就实现了复杂的选择功能
  • 状态管理:组件内置了展开/收起、搜索、键盘导航等状态
  • 类型安全:TS 支持,提供完整的类型定义

业务层面

  • 快速迭代:能快速搭建界面原型
  • 用户体验:提供符合用户习惯的交互方式
  • 维护成本低:统一的组件升级,全局受益

4. 是否还需要 CSS 样式

基础样式

  • 内置样式:Ant Design 已提供默认美观样式
  • 主题定制:可通过配置修改整体主题(颜色、字体、间距等)

自定义样式场景

TypeScript 复制代码
import { Select, Button, Space, message } from "antd";
import { SearchOutlined } from "@ant-design/icons";

何时需要自定义样式

  • 品牌定制:需要匹配公司品牌色
  • 特殊布局:超出组件库默认布局需求
  • 响应式:特殊设备适配需求

5. 总结

Ant Design 让原本复杂的下拉选择、按钮交互、布局排列等工作变得简单,只需要关注业务逻辑,而不需要处理组件的视觉效果和交互细节。这种做法大大提升了开发效率,同时保证了用户体验的一致性。

2 困惑:怎么项目设计

我还有想做优化的方向,但是我不会画草图不会写技术方案,自然语言描述太空洞了,没有具体的代码结构化思维。

也许在学习开发的初期这个并不是重点,因为我读了一些有关架构和项目设计的文章,我感到这期中的设计哲学都是经验的积累,是项目一个一个实践的坑踩出来的,是在一开始懵懵懂懂连结构也不知道的时候慢慢体会出来的。

我给自己的建议是:

我还在学习开发的初期,不用追求成熟的、完美的架构设计,不用要求自己去写出漂亮的技术方案。

可是...把需求直接抽象成技术方案的能力要怎么培养?

求助deepseek老师。

---------------------------

你的思考非常深刻!你已经触及了软件工程的核心------如何将模糊需求转化为结构化的技术实现 。这确实是经验积累的过程,但有一套可训练的方法可以帮助你系统性地培养这种能力。

从"直接编码"到"设计思维"的演进路径

第一阶段:先学会"暴力翻译"(你现在的位置)

核心能力:将需求直接转化为代码,不考虑太多设计。

练习方法:

  1. 功能列表 → 函数列表

    • 需求:"用户能注册、登录、查看个人信息"

    • 直接翻译:

    python 复制代码
    def register(username, password, email):
        # 直接写数据库插入
        
    def login(username, password):
        # 直接查数据库
        
    def get_user_info(user_id):
        # 直接返回用户数据
  2. 关键技巧:使用"场景模拟法"

    cpp 复制代码
    # 想象一个真实用户的操作流程
    # 1. 用户打开注册页面
    # 2. 输入信息,点击提交
    # 3. 系统检查用户名是否重复
    # 4. 保存到数据库
    # 5. 发送欢迎邮件
    
    # 把这些步骤直接写成代码注释,然后填充实现

第二阶段:识别"重复模式"(过渡阶段)

核心能力:发现代码中的重复和相似结构。

练习方法:

  1. 三遍法则:当你第三次写相似的代码时,停下来思考:

    python 复制代码
    # 第一次
    def get_product_by_id(id):
        conn = get_db_connection()
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM products WHERE id = %s", (id,))
        # ...
        
    # 第二次  
    def get_user_by_id(id):
        conn = get_db_connection()
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM users WHERE id = %s", (id,))
        # ...
        
    # 第三次 - 停下来!提取模式
    class DatabaseHelper:
        @staticmethod
        def get_by_id(table, id):
            conn = get_db_connection()
            cursor = conn.cursor()
            cursor.execute(f"SELECT * FROM {table} WHERE id = %s", (id,))
            # ...
  2. 维护一个"模式发现日志"

    复制代码
    日期:2024-01-15
    重复模式:多个地方都需要验证用户权限
    出现位置:订单创建、文章删除、文件上传
    提取方案:创建一个 decorator @require_login

第三阶段:培养"拆解思维"(结构化能力)

核心能力:将大问题分解为小问题,并识别依赖关系。

具体训练方法:

方法1:使用"名词动词法"

规则 :从需求中找出所有名词 (这些可能成为类/表),找出所有动词(这些可能成为方法/函数)。

例子: "用户下单购买商品,系统扣除库存并生成订单"

  • 名词:用户、商品、库存、订单

  • 动词:下单、购买、扣除、生成

初步设计:

python 复制代码
# 名词变成类
class User:
    def place_order(self, items): pass

class Product:
    pass

class Inventory:
    def deduct(self, product_id, quantity): pass

class Order:
    @staticmethod
    def create(user_id, items): pass

# 动词变成方法
def purchase(user_id, product_id, quantity):
    # 调用上面各个对象的方法
    user = User.get(user_id)
    order = user.place_order(...)
    inventory.deduct(...)
方法2:练习"分而治之"卡片法

准备一些卡片或便签纸,按照这个流程:

  1. 功能卡:每张卡片写一个具体功能

  2. 数据卡:每张卡片写一种需要存储的数据

  3. 关系卡:用箭头连接卡片,表示依赖关系

例子:设计一个博客系统

cpp 复制代码
功能卡:[发布文章] [评论文章] [用户关注]
数据卡:[用户信息] [文章内容] [评论内容] [关注关系]
关系卡:[发布文章] → 需要 [用户信息] + [文章内容]
        [评论文章] → 需要 [用户信息] + [文章内容] + [评论内容]

第四阶段:掌握"设计对话法"(培养架构直觉)

核心能力:与需求进行"对话",挖掘隐含的技术要求。

练习模板:

复制代码
## 设计对话:设计一个短链接系统

### 问需求:
Q1: 预计每天生成多少短链接?(→ 决定存储方案)
Q2: 短链接需要永久有效还是有时效?(→ 决定缓存策略)
Q3: 跳转性能要求多高?(→ 决定架构复杂度)

### 自问自答:
A1: 假设每天100万,数据量不大,MySQL足够。
A2: 大部分短链接访问集中在生成后7天内(→ 用Redis做热数据缓存)。
A3: 跳转要快,300ms内(→ 需要CDN或边缘计算)。

### 得出结构:
1. 生成服务:接收长链接 → 生成短码 → 存MySQL
2. 跳转服务:接收短码 → 查Redis → 查MySQL → 302跳转
3. 缓存策略:7天TTL,LRU淘汰

专项训练:从零设计小项目

第一周:CRUD应用设计

  • 任务:设计一个图书管理系统

  • 要求:用纯文本画出模块关系

复制代码
[用户界面] → [图书控制器] → [图书服务] → [图书仓库] → [数据库]
                            ↓
                     [借阅服务] → [借阅记录表]

第二周:识别设计模式

  • 任务:重构一个简单的电商购物车

  • 要求:识别哪些地方可以用模式

python 复制代码
# 发现:不同的商品有不同的计价策略
# 应用策略模式
class PricingStrategy:
    def calculate_price(self, item): pass

class NormalPrice(PricingStrategy):
    def calculate_price(self, item):
        return item.price * item.quantity

class DiscountPrice(PricingStrategy):
    def calculate_price(self, item):
        return item.price * item.quantity * 0.8

class Cart:
    def __init__(self, pricing_strategy):
        self.strategy = pricing_strategy

第三周:设计API接口

  • 任务:为博客系统设计REST API

  • 要求:用Markdown写API文档

复制代码
## 文章相关API
### GET /api/articles
- 功能:获取文章列表
- 参数:page, size, category
- 响应:{articles: [], total: 100}

### POST /api/articles
- 功能:创建文章
- 请求体:{title: "xxx", content: "yyy", tags: []}
- 认证:需要JWT token

实用工具:从"自然语言"到"技术方案"的转换器

当你接到需求时,使用这个检查清单

  1. 功能边界:这个系统到底要做什么?不做什么?

  2. 数据模型:需要存储哪些数据?它们的关系是什么?

  3. 用户流程:用户如何使用?一步步的交互是什么?

  4. 性能要求:有多少用户?需要多快?

  5. 扩展考虑:未来可能增加什么功能?

培养设计思维的日常练习

  1. 重构练习:每周找一个自己的旧代码,尝试重新设计

  2. 开源阅读:每天阅读一个GitHub项目的架构文档

  3. 设计日记:记录每天遇到的设计决策和理由

  4. 结对设计:和同事/朋友一起讨论同一个需求的设计

关键心态调整

  1. 接受不完美:第一版设计通常有缺陷,这完全正常

  2. 迭代式设计:设计是不断演进的过程,不是一次性产物

  3. 从实现反推:先写出能工作的代码,然后思考"如果重写,我会怎么组织"

  4. 注重可读性:好的设计首先是容易理解的

推荐学习路径

复制代码
第1-2月:专注“功能实现”
  ↓
第3-4月:学习“设计模式”(从《Head First设计模式》开始)
  ↓  
第5-6月:练习“系统分解”(尝试设计中等复杂度系统)
  ↓
第7-8月:研究“架构原则”(SOLID、DRY、KISS等)
  ↓
持续:参与真实项目,从代码维护中学习

记住,设计能力 = 经验 × 反思。每完成一个项目,问自己三个问题:

  1. 哪些设计决策是正确的?

  2. 哪些地方如果重做我会改进?

  3. 这个项目的核心设计思想是什么?

你现在正处在最宝贵的学习阶段------意识到了设计的重要性,但又感到困惑。

这种困惑正是成长的起点。

不要追求一次性学会,而要追求每次都比上次多想一层。

相关推荐
用泥种荷花2 小时前
VueCropper加载OBS图片跨域问题
前端
lkbhua莱克瓦242 小时前
MySQL介绍
java·开发语言·数据库·笔记·mysql
董世昌412 小时前
什么是事件冒泡?如何阻止事件冒泡和浏览器默认事件?
java·前端
Bigger2 小时前
在 React 里优雅地 “隐藏 iframe 滚动条”
前端·css·react.js
小沐°2 小时前
vue3-ElementPlus出现Uncaught (in promise) cancel 报错
前端·javascript·vue.js
栀秋6662 小时前
LangChain Memory 实战指南:让大模型记住你每一句话,轻松打造“有记忆”的AI助手
javascript·langchain·llm
kylezhao20192 小时前
如何在 C# 项目中使用 NLog 进行日志记录
开发语言·c#
好度2 小时前
配置java标准环境?(详细教程)
java·开发语言
笨笨马甲2 小时前
Qt TCP连接硬件设备
开发语言·qt·tcp/ip