agentmentoragentmentor

第 04 节:数据先别联网:对象、数组、props、列表

本节 objectives:

  • 能用对象表示一条内容,用数组表示多条内容。
  • 能用 props 把数据传给组件。
  • 能用 map 渲染列表,并给列表项加 key

先修:会写组件、页面、简单路由 | 上一节 << 03 | 下一节 05 >>

先学本地数据,再学联网数据

很多 Next.js 教程很快进入数据库、API、缓存。对 JS/React 不熟的人来说,那会把三个问题搅在一起:数据长什么样、React 怎么显示它、Next.js 从哪里取它。

这一节只处理第一和第二个问题。先把数据写在文件里,用对象和数组表示内容,再用 props 和 map 让页面自动生成卡片。MDN 把对象描述为属性集合,数组的 map 会对每个元素调用函数并返回一个新数组12。React 列表渲染正好用这个能力3

讲解

对象是一条记录。
一条课程记录可以这样写:

tsx
const lesson = {  title: "认识页面",  minutes: 30,  done: true,};

lesson.title 取出标题,lesson.minutes 取出时长。

数组是多条记录。
多节课可以放进数组:

tsx
const lessons = [  { title: "认识页面", minutes: 30 },  { title: "写组件", minutes: 40 },];

props 是组件收到的数据。
React 官方把 props 解释成传给组件的信息4。你可以把 titleminutes 传给 LessonCard,让一个组件显示不同内容。

map 把数据数组变成组件数组。
React 渲染列表时,每个列表项需要稳定的 key,帮助 React 识别哪一项变了3。初学阶段优先用真实 id,不要随手用数组下标。

跟我做一遍(worked example)

目标:在首页渲染三张学习卡片。

tsx
const lessons = [  { id: "page", title: "认识页面", minutes: 30 },  { id: "component", title: "写组件", minutes: 40 },  { id: "route", title: "做路由", minutes: 35 },];
function LessonCard({  title,  minutes,}: {  title: string;  minutes: number;}) {  return (    <article>      <h2>{title}</h2>      <p>预计 {minutes} 分钟</p>    </article>  );}
export default function Home() {  return (    <main>      <h1>Next.js 学习计划</h1>      <section>        {lessons.map((lesson) => (          <LessonCard            key={lesson.id}            title={lesson.title}            minutes={lesson.minutes}          />        ))}      </section>    </main>  );}

为什么这样写:

  • lessons 是数据,不直接写一堆重复 JSX。
  • LessonCard 只关心自己收到的 props。
  • map 遍历数组,每条数据生成一张卡片。
  • key={lesson.id} 使用稳定 id,不是显示给用户看的内容。

换你补全(faded example)

下面要渲染两个作品卡片。补全 ProjectCard 的 props 和 map 里的调用。

tsx
const projects = [  { id: "notes", name: "学习笔记站", status: "进行中" },  { id: "portfolio", name: "个人作品集", status: "计划中" },];
function ProjectCard({ ______, ______ }: { name: string; status: string }) {  return (    <article>      <h2>{name}</h2>      <p>{status}</p>    </article>  );}
export default function ProjectsPage() {  return (    <main>      <h1>作品</h1>      {projects.map((project) => (        <ProjectCard          key={______}          name={______}          status={______}        />      ))}    </main>  );}

参考答案:

tsx
function ProjectCard({ name, status }: { name: string; status: string }) {  return (    <article>      <h2>{name}</h2>      <p>{status}</p>    </article>  );}
{projects.map((project) => (  <ProjectCard    key={project.id}    name={project.name}    status={project.status}  />))}

关键判断点:props 名字要和组件参数一致;keyproject.id;显示内容用 project.nameproject.status

小结 + 通向下一节

你已经能把数据和界面拆开:数据是数组,组件负责显示,map 负责批量生成。下一节给这些页面加基本视觉结构,但仍保持代码可读。

Footnotes

  1. MDN: Working with Objects — https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_objects

  2. MDN: Array.prototype.map — https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map

  3. React: Rendering Lists — https://react.dev/learn/rendering-lists 2

  4. React: Passing Props to a Component — https://react.dev/learn/passing-props-to-a-component

练习

Level 1:把三条数据写成数组。
做法:写一个 goals 数组,包含三条学习目标。每条至少有 idtitledone

提示 1

一条对象用 {}

提示 2

多条对象放进 []。 Level 2:渲染目标列表。
做法:写一个 GoalCard 组件,用 goals.map 渲染三张卡片。

看参考答案
tsx
const goals = [  { id: "run", title: "能跑起项目", done: true },  { id: "route", title: "能新增页面", done: true },  { id: "state", title: "能做交互", done: false },];
自评