M
← 文章列表
·4 分钟阅读·979ReactNext.js学习笔记

React 组件基础:JSX、Props、导入导出

搞懂 .tsx 文件是什么,JSX 语法怎么写,组件怎么传参,export default 和具名导出有什么区别。

React 组件基础:JSX、Props、导入导出

.tsx 是什么文件

后缀 含义
.ts TypeScript
.tsx TypeScript + JSX(能在代码里写 HTML 标签)
.js JavaScript
.jsx JavaScript + JSX

我们的页面和组件都用 .tsx,因为需要在 TypeScript 里写 HTML 结构。

JSX 是什么

JSX 是 React 发明的语法,让你在 JS/TS 里直接写 HTML

// 这就是 JSX,看起来像 HTML,但在 .tsx 文件里
function Hello() {
  return <h1>你好世界</h1>;
}

最大的特点是用 {} 插入 JS 表达式:

const name = "Mary";
const count = 3;

<h1>你好,{name}</h1>                     // → 你好,Mary
<p>共 {count} 篇文章</p>                  // → 共 3 篇文章
<p>共 {count * 2} 篇</p>                  // → 可以做运算
<p>{count > 0 ? "有文章" : "没有文章"}</p> // → 可以写条件

JSX 和 HTML 的区别

两者 99% 一样,只有几处不同:

// 1. class → className(class 是 JS 关键字)
<div class="box">      // ❌
<div className="box">  // ✅

// 2. 自闭合标签必须加 /
<img src="x.png">   // ❌
<img src="x.png" /> // ✅
<br>                // ❌
<br />              // ✅

// 3. 注释写法不同
<!-- 注释 -->   // ❌ HTML 注释在 JSX 里不能用
{/* 注释 */}   // ✅

组件是什么

组件就是返回 JSX 的函数,是可以复用的 UI 片段:

// 定义一个文章卡片组件
function PostCard() {
  return (
    <div>
      <h2>文章标题</h2>
      <p>文章摘要</p>
    </div>
  );
}

// 使用组件,就像使用 HTML 标签
<PostCard />

规则:组件名必须大写字母开头,用来和普通 HTML 标签区分(<div> vs <PostCard />)。

Props:给组件传数据

Props 就是组件的参数,从外部传入数据:

// 定义 Props 类型
interface PostCardProps {
  title: string;
  date: string;
}

// 接收 Props(用对象解构直接取出字段)
function PostCard({ title, date }: PostCardProps) {
  return (
    <div>
      <h2>{title}</h2>
      <p>{date}</p>
    </div>
  );
}

// 使用时传入数据
<PostCard title="你好世界" date="2026-04-05" />

{ title, date }对象解构,等价于:

function PostCard(props: PostCardProps) {
  const title = props.title;
  const date = props.date;
}

组件的完整结构

// 1. 导入依赖
import Link from "next/link";

// 2. 定义 Props 类型
interface PostCardProps {
  title: string;
  date: string;
}

// 3. 组件函数(export default = 默认导出)
export default function PostCard({ title, date }: PostCardProps) {
  
  // 4. 普通 JS 逻辑
  const formattedDate = new Date(date).toLocaleDateString("zh-CN");
  
  // 5. 返回 JSX
  return (
    <div>
      <h2>{title}</h2>
      <time>{formattedDate}</time>
    </div>
  );
}

export default vs 具名导出

// 默认导出:一个文件只能有一个
// 适合:这个文件的"主角"
export default function PostCard() {}

// 导入时名字可以随便起
import PostCard from "./PostCard";
import Card from "./PostCard"; // 也合法,是同一个东西


// 具名导出:一个文件可以有多个
// 适合:工具函数、类型定义等
export function getAllPosts() {}
export function getAllTags() {}
export interface PostMeta {}

// 导入时必须花括号,名字必须对得上
import { getAllPosts, getAllTags } from "./posts";

map 渲染列表

在 React 里,用 map 把数组渲染成 JSX 列表:

const posts = [
  { slug: "a", title: "文章一" },
  { slug: "b", title: "文章二" },
];

// 每个元素渲染一个 PostCard
// key 是必须的,帮助 React 追踪每个元素
{posts.map((post) => (
  <PostCard key={post.slug} title={post.title} />
))}

Server Component vs Client Component

这是 Next.js 特有的概念:

// Server Component(默认):在服务器上运行
// 可以直接读文件、查数据库
// 不能用 useState、useEffect、事件处理
export default function PostsPage() {
  const posts = getAllPosts(); // 直接读文件,完全合法
  return <div>{/* ... */}</div>;
}

// Client Component:在浏览器里运行
// 文件顶部加 "use client"
"use client";
import { useState } from "react";

export default function SearchBar() {
  const [query, setQuery] = useState(""); // 需要 useState
  return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
}

选择原则: 默认用 Server Component,只有需要交互(点击、输入、状态)时才加 "use client"