新闻详情

新闻详情

首页 / 资讯中心 / 详情

用 Redwood 方式构建组件:以评论组件为例的 Storybook 与测试全流程

发布时间:2026/11/7 1:26:34来源:尧图网络
用 Redwood 方式构建组件:以评论组件为例的 Storybook 与测试全流程
后端前端Web框架开发工具【免费下载链接】redwoodRedwoodGraphQL项目地址https://gitcode.com/gh_mirrors/re/redwood点击查看免费下载导读本文基于 Redwood 官方教程第五章用 Redwood 的方式构建组件Building a Component the Redwood Way展开以给博客添加评论功能为实战场景完整演示 Redwood 开发工作流的经典路径先用yarn rw g component生成组件骨架再借助 Storybook 以交互方式打磨组件外观与数据结构最后用yarn rw test为组件编写行为级测试。读完本文你将掌握 Redwood 中生成 → 可视化开发 → 测试验证的组件开发闭环以及time标签 datetime属性这类容易被忽略的机器可读性细节。一、需求拆解评论功能的两条主线在开始动手之前先明确我们要构建的功能。博客缺少评论目标很简单让读者在文章下面留下他们完全理性、有理有据的评论。整个功能可以被拆成两大块评论表单与创建Comment form and creation用户输入并提交评论评论检索与展示Comment retrieval and display把已存在的评论取出来并渲染到页面上。两条主线先后顺序没有强制要求。为了循序渐进教程选择先做取数 展示再去做更复杂的表单 Service 创建。当然正如教程所说这是 Redwood连表单和 Service 也没有那么复杂。这种先展示、后写入的顺序安排也符合组件开发的直觉先把静态展示形态确定下来数据结构、样式、测试再接入数据写入能显著降低心智负担。二、用生成器创建 Comment 组件Storybook 先行2.1 生成组件骨架Redwood 的 CLI 提供了组件生成器一条命令即可产出组件文件yarn rw g component Comment执行后Storybook 会自动刷新并生成一个开箱即用的 Generated Comment story。从仓库源码看这条命令背后做了不少事情。component.js 中files()函数定义了生成器的产出逻辑生成主组件文件web/src/components/Comment/Comment.jsx或.tsx生成测试文件web/src/components/Comment/Comment.test.jsx或.test.tsx生成 Story 文件web/src/components/Comment/Comment.stories.jsx或.stories.tsx。其中 TS 与 JS 版本会使用不同的模板JS 版本的主组件内容由transformTSToJS从 TS 模板转换而来而 Story 模板则分别有 stories.tsx.template 与stories.jsx.template两个独立文件因为 TS 模板注释中含类型信息。是否生成测试和 Story 文件取决于命令选项options.stories与options.tests默认都会生成。主组件的初始模板component.tsx.template内容非常简单仅仅渲染一个标题和提示文字const Comment () { return ( div h2{Comment}/h2 p{Find me in web/src/components/Comment/Comment.tsx}/p /div ) } export default Comment生成的测试模板test.tsx.template也只做了最基础的事情——渲染组件不抛异常import { render } from redwoodjs/testing/web import Comment from ./Comment describe(Comment, () { it(renders successfully, () { expect(() { render(Comment /) }).not.toThrow() }) })这就是教程中所说默认测试只是确保不抛错的来源这是生成器给所有组件的最低保障。2.2 明确组件的数据契约接下来要思考我们希望用户提供什么、展示什么最简方案是只收集姓名和评论正文再额外带上评论的创建时间。于是 Comment 组件需要接收一个包含三个属性的comment对象name评论者姓名createdAt评论创建时间body评论正文。JavaScript 版本直接解构 propsconst Comment ({ comment }) { return ( div h2{comment.name}/h2 time dateTime{comment.createdAt}{comment.createdAt}/time p{comment.body}/p /div ) } export default CommentTypeScript 版本则需要先定义一个临时的 Props 类型教程特意注明这只是临时类型后续接入 GraphQL 生成类型后会替换// Just a temporary type. Well replace this later interface Props { comment: { name: string createdAt: string body: string } } const Comment ({ comment }: Props) { return ( div h2{comment.name}/h2 time dateTime{comment.createdAt}{comment.createdAt}/time p{comment.body}/p /div ) } export default Comment注意这里 TypeScript 的类型信息是手工声明的内联结构。在 Redwood 中这类类型最终往往会被替换为由 SDLSchema Definition Language与 Cell 生成出的类型以实现端到端的类型安全——这也是教程中Just a temporary type注释的含义。2.3 修复 Story补上缺失的 props保存文件后Storybook 会立刻报错——因为 Story 仍然按无 props渲染组件而组件现在要求comment对象。需要更新 Story 文件传入一个符合数据契约的示例对象import Comment from ./Comment export const generated () { return ( Comment comment{{ name: Rob Cameron, body: This is the first comment!, createdAt: 2020-01-01T12:34:56Z }} / ) } export default { title: Components/Comment, component: Comment, }TypeScript 版本完全一致import Comment from ./Comment export const generated () { return ( Comment comment{{ name: Rob Cameron, body: This is the first comment!, createdAt: 2020-01-01T12:34:56Z }} / ) } export default { title: Components/Comment, component: Comment, }保存后 Storybook 重新加载组件即可正常渲染。:::info 关于日期格式的一个重要提示 时间值最终会以ISO8601 格式如2020-01-01T12:34:56Z从 GraphQL 返回因此 Story 中必须提供一个该格式的示例值。这保证 Story 与真实运行时数据形态一致避免开发环境好好的、一接真数据就崩的落差。 :::三、让组件像成品样式与日期格式化基础展示没有问题后为组件加上一点样式和日期转换让它成为一个设计完成的组件。我们新增一个formattedDate工具函数把 ISO8601 字符串解析为Date对象提取出日期、月份长名称如 January和年份拼成2 January 2020这样易读的格式同时保留time标签的dateTime属性用于承载机器可读的原始时间戳。JavaScript 版本const formattedDate (datetime) { const parsedDate new Date(datetime) const month parsedDate.toLocaleString(default, { month: long }) return ${parsedDate.getDate()} ${month} ${parsedDate.getFullYear()} } const Comment ({ comment }) { return ( div classNamebg-gray-200 p-8 rounded-lg header classNameflex justify-between h2 classNamefont-semibold text-gray-700{comment.name}/h2 time classNametext-xs text-gray-500 dateTime{comment.createdAt} {formattedDate(comment.createdAt)} /time /header p classNametext-sm mt-2{comment.body}/p /div ) } export default CommentTypeScript 版本的关键差异在于入参类型formattedDate接收的参数类型声明为ConstructorParameterstypeof Date[0]即Date构造函数第一个参数的类型string | number | Date这样既能接受 ISO8601 字符串又保持类型安全const formattedDate (datetime: ConstructorParameterstypeof Date[0]) { const parsedDate new Date(datetime) const month parsedDate.toLocaleString(default, { month: long }) return ${parsedDate.getDate()} ${month} ${parsedDate.getFullYear()} } // Just a temporary type. Well replace this later interface Props { comment: { name: string createdAt: string body: string } } const Comment ({ comment }: Props) { return ( div classNamebg-gray-200 p-8 rounded-lg header classNameflex justify-between h2 classNamefont-semibold text-gray-700{comment.name}/h2 time classNametext-xs text-gray-500 dateTime{comment.createdAt} {formattedDate(comment.createdAt)} /time /header p classNametext-sm mt-2{comment.body}/p /div ) } export default Comment样式上用的是 Tailwind 工具类外层卡片bg-gray-200 p-8 rounded-lg头部用 flex 让姓名左对齐、时间右对齐正文用小号文字。这样组件就从一个裸数据展示器变成了一个有完整视觉形态的 UI 元素此时再回到 Storybook 中可以看到最终效果。四、用测试锁定组件行为样式和展示都正确了接下来用测试确认组件确实按预期工作。测试要点验证作者姓名、评论正文、以及评论发布日期的展示——并且要同时验证用户可读的格式化文本和机器可读的datetime属性。测试代码如下import { render, screen } from redwoodjs/testing import Comment from ./Comment describe(Comment, () { it(renders successfully, () { const comment { name: John Doe, body: This is my comment, createdAt: 2020-01-02T12:34:56Z, } render(Comment comment{comment} /) expect(screen.getByText(comment.name)).toBeInTheDocument() expect(screen.getByText(comment.body)).toBeInTheDocument() const dateExpect screen.getByText(2 January 2020) expect(dateExpect).toBeInTheDocument() expect(dateExpect.nodeName).toEqual(TIME) expect(dateExpect).toHaveAttribute(datetime, comment.createdAt) }) })TypeScript 版本相同仅扩展名与导入路径不同.test.tsximport { render, screen } from redwoodjs/testing import Comment from ./Comment describe(Comment, () { it(renders successfully, () { const comment { name: John Doe, body: This is my comment, createdAt: 2020-01-02T12:34:56Z, } render(Comment comment{comment} /) expect(screen.getByText(comment.name)).toBeInTheDocument() expect(screen.getByText(comment.body)).toBeInTheDocument() const dateExpect screen.getByText(2 January 2020) expect(dateExpect).toBeInTheDocument() expect(dateExpect.nodeName).toEqual(TIME) expect(dateExpect).toHaveAttribute(datetime, comment.createdAt) }) })这段测试值得逐条拆解expect(screen.getByText(comment.name)).toBeInTheDocument()验证姓名文本被渲染expect(screen.getByText(comment.body)).toBeInTheDocument()验证正文文本被渲染screen.getByText(2 January 2020)验证格式化后的日期文本这与前文中测试文章截断文本的思路一致expect(dateExpect.nodeName).toEqual(TIME)验证包裹该文本的元素确实是time标签expect(dateExpect).toHaveAttribute(datetime, comment.createdAt)验证datetime属性携带原始时间戳。第 4、5 条断言看起来像是过度测试但这是有明确目的的datetime属性的存在意义是提供机器可读的时间戳浏览器理论上可以据此做诸如自动转换本地时区、注入日历提醒等能力。断言这两点就是确保我们不会在日后的重构中无意间破坏这种机器可读性。它和测试截断文本在理念上一脉相承——你关心什么行为就锁定什么行为。测试所用的render、screen等 API 全部来自redwoodjs/testing。在仓库源码中packages/testing/src/web/index.ts 通过export * from testing-library/react重新导出了 React Testing Library 的全部能力Redwood 的测试生态因此与社区标准工具链完全兼容。运行测试如果测试还没有在另一个终端窗口中运行现在启动yarn rw testRedwood 的测试 runner 会以 watch 模式运行保存测试文件后自动重跑。:::info 如果改了日期格式化逻辑测试会不会跟着坏会的——正如改动截断长度就要同步修改截断文本的断言一样。一个可选的替代方案是把日期格式化逻辑抽成一个可从组件导出的独立函数然后在测试中导入该函数来生成期望值。这样当你改动格式化公式时测试因为与组件共享同一个函数而自动保持通过无需手工同步两处逻辑。从组件中导出纯函数并在测试中复用的做法在 Redwood 中非常常见——它既保证了测试与实现的同步性也让格式化这类纯逻辑可以被独立单元测试。 :::五、小结Redwood 的组件开发闭环回顾本章的完整流程可以提炼出 Redwood 推荐的组件开发模式生成yarn rw g component Comment一键生成组件、测试、Story 三件套源码见 component.js定义数据契约明确组件接收的 props本例为name、createdAt、bodyTS 项目同步声明类型Storybook 可视化迭代为 Story 提供符合契约的示例数据在浏览器中即时调整样式与展示逻辑测试锁定行为不止断言渲染不报错而是锁定真实业务行为——文本内容、元素语义time、机器可读属性datetime运行yarn rw test持续验证。这套生成器 Storybook 测试的组合拳贯穿 Redwood 的日常开发。本章只完成了评论功能的展示半边接下来将进入更复杂的另一半——评论表单的创建与 Service 层的写入逻辑。那时Comment组件积累的展示与测试基础会直接复用这也正是用 Redwood 的方式渐进式构建功能的精髓所在。赞分享后端前端Web框架开发工具【免费下载链接】redwoodRedwoodGraphQL项目地址https://gitcode.com/gh_mirrors/re/redwood点击查看免费下载相关推荐以 Redwood 方式构建组件从 Storybook 到测试的 Comment 组件实战以 Redwood 方式构建组件从 Storybook 到测试的 Comment 组件实战 这篇技术指南以 Redwood 官方教程第六章《Building后端前端Web框架开发工具Redwood 教程用 Cell 构建评论列表CommentsCell——从 Storybook 开发到组件测试全流程Redwood 教程用 Cell 构建评论列表CommentsCell——从 Storybook 开发到组件测试全流程 本篇教程是 Redwood 官方教后端前端Web框架开发工具Redwood 组件开发实战以 Comment 组件为例解析组件生成 → Storybook → 测试的 The Redwood WayRedwood 组件开发实战以 Comment 组件为例解析组件生成 → Storybook → 测试的 The Redwood Way Redwood后端前端Web框架开发工具上一篇终极指南ggml混合精度训练中FP16与FP32的最佳实践下一篇终极指南co代码规范——编写优雅异步代码的10条黄金准则创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

【外设】之大彩串口显示屏 2026/11/6 6:37:16

【外设】之大彩串口显示屏

大彩串口屏初步使用 1 .官网下载 STM32 屏幕 GUI 设计资料 http://www.gz-dc.com/category/typeid/4112 找到 STM32 Keil 工程,移植相关代码因项目而异进行移植,由于项目简单,本人只对用到的指令接口进行修改。 比如:注意事项&…

阅读更多 →
无法下载Windows系统iso文件 2026/11/7 0:39:20

无法下载Windows系统iso文件

当我遇到这个问题的时候,我打开了一个网站: 登录 然后我打算下载的时候: 突然那个官方的连接就可以下载了:

阅读更多 →
【清华代码熊】DeepSeek V4.1 Flash 后训练详解 2026/11/6 1:10:54

【清华代码熊】DeepSeek V4.1 Flash 后训练详解

📌 上期解析了 DeepSeek V4.1 Flash 模型架构改进,本期解析 DeepSeek V4.1 Flash 预训练/后训练技术: 🌟 预训练:45T 文本 多模态混合语料、直接训练 sparse attention(取消 DeepSeek V4 的 dense 冷启动&…

阅读更多 →
Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ... 2026/11/6 17:25:36

Shuffle-R1: Efficient RL framework for Multimodal Large Language Models via Data-centric Dynamic ...

文章主要内容和创新点 主要内容 本文聚焦于多模态大语言模型(MLLM)强化学习(RL)训练中的效率问题,提出了一个名为Shuffle-R1的框架。研究发现,当前RL训练存在两个关键缺陷: 优势值坍缩(Advantage Collapsing):批次中大多数优势值集中在零附近,导致有效梯度信号被淹…

阅读更多 →
PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction 2026/11/6 14:29:05

PRvL: Quantifying the Capabilities and Risks of Large Language Models for PII Redaction

一、文章主要内容总结 本文聚焦于利用大型语言模型(LLMs)实现个人身份信息(PII)脱敏的研究,旨在解决传统脱敏方法(如基于规则的系统、领域特定命名实体识别(NER)模型)泛化能力差、跨格式/跨语境适应性弱的问题。 研究通过全面评估多种LLM架构(包括密集型LLM(D-LLM…

阅读更多 →
LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model 2026/11/6 14:29:07

LLaVA-RE: Binary Image-Text Relevancy Evaluation with Multimodal Large Language Model

文章主要内容和创新点 主要内容 本文聚焦于二进制图像-文本相关性评估任务(判断图像与文本“相关”或“不相关”),针对该任务中文本格式多样、相关性定义随场景变化等挑战,提出了基于多模态大语言模型(MLLM)的解决方案LLaVA-RE。 模型设计:LLaVA-RE基于LLaVA 1.5架构,…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉