人人都会AI编程

3.2 条件渲染:v-if /v-else/v-show 的用法与区别

更新时间:2026-07-10

什么是 Props

Props(Properties 的缩写)是 React 组件对外暴露的接口,是父组件向子组件传递数据的唯一方式。你可以把 Props 理解为函数的参数:组件是一个函数,Props 是传入的实参,组件根据这些参数返回对应的 UI。

function Greeting({ name }) {
  return <h1>你好,{name}!</h1>;
}

// 使用组件时传递 Props
<Greeting name="张三" />

在这个例子中,name 就是 Greeting 组件的 Props,它的值是 "张三"。组件内部通过解构参数直接使用这个值。

Props 是只读的

React 有一条严格的规则:组件绝不能修改自己的 Props。Props 是“只读”的,类似于纯函数的参数——相同的输入必须产生相同的输出,不能在函数内部篡改传入的值。

// ❌ 错误:尝试修改 Props
function Welcome({ user }) {
  user.name = '李四'; // 不允许!
  return <div>{user.name}</div>;
}

// ✅ 正确:只读取 Props,不做修改
function Welcome({ user }) {
  return <div>{user.name}</div>;
}

之所以设定这个规则,是为了保持单向数据流的纯粹性。如果子组件能随意修改 Props,数据的流向就会变得混乱,整个应用的状态将难以追踪。当你需要根据用户交互改变界面时,应该通过状态(State)回调函数通知父组件来触发更新,而不是直接修改 Props。

传递任意类型的值

Props 可以传递 JavaScript 中任意类型的值:

  • 字符串<Button text="提交" />
  • 数字<Pagination current={1} total={10} />
  • 布尔值<Modal visible={true} />(省略值时默认为 true:<Modal visible />
  • 数组<List items={['A', 'B', 'C']} />
  • 对象<UserCard user={{ name: '张三', age: 25 }} />
  • 函数(极其常见):<Button onClick={handleClick} />
  • JSX 元素(作为 children 或自定义 Prop):<Card header={<h2>标题</h2>} />
// 实际案例:一个弹窗组件
function Modal({ visible, title, children, onClose }) {
  if (!visible) return null;
  return (
    <div className="modal-overlay">
      <div className="modal">
        <div className="modal-header">
          <h2>{title}</h2>
          <button onClick={onClose}>关闭</button>
        </div>
        <div className="modal-body">{children}</div>
      </div>
    </div>
  );
}

// 使用
<Modal
  visible={isOpen}
  title="用户详情"
  onClose={() => setIsOpen(false)}
>
  <p>这里是弹窗的具体内容</p>
</Modal>

Props 的默认值

当某些 Props 未传入时,你可能希望组件有一个回退的默认值。可以通过解构时的默认值语法实现:

function Button({ text = '点击', size = 'medium', disabled = false }) {
  return (
    <button
      className={`btn btn-${size}`}
      disabled={disabled}
    >
      {text}
    </button>
  );
}

// 不传 text 时默认显示"点击"
<Button />;
<Button text="删除" size="small" />;

这种方式比使用 defaultProps 静态属性(类组件时代的写法)更加直观且符合现代 JavaScript 习惯。

使用展开运算符传递 Props

当你有多个 Props 需要传递,或者需要将某个对象的所有属性拆开传入时,可以使用展开运算符:

const userInfo = {
  name: '王五',
  age: 30,
  role: 'admin',
};

<UserCard {...userInfo} />;

// 等价于
<UserCard name="王五" age={30} role="admin" />

这在实际开发中很常见,例如将父组件接收到的所有 Props 透传给子组件:

function PrimaryButton(props) {
  return <button className="primary" {...props} />;
}

// 使用
<PrimaryButton onClick={handleClick} disabled={true}>提交</PrimaryButton>

需要注意的是,过度使用展开运算符可能让 Props 的来源和内容变得不清晰,建议在明确需要批量传递且结构稳定的场景下使用。

Props 的命名与设计原则

为了让组件易用且易于维护,Props 设计应遵循以下原则:

  1. 语义清晰:使用描述性的名称,比如 isLoading 而不是简单的 flag
  2. 最小化暴露:只暴露组件真正需要的数据,避免传递整个大对象。例如,需要用户名时只传 username,而不是整个 user 对象(除非组件确实需要对象的多个字段)。
  3. 保持一致的命名习惯:布尔值通常以 ishasshould 开头(如 isVisiblehasError),事件处理函数以 on 开头(如 onClickonSubmit)。
  4. 必要的类型检查:在 TypeScript 中为 Props 定义 interface,在 JavaScript 中可以使用 PropTypes(较少用)提供运行时警告。
// TypeScript 示例
interface UserCardProps {
  name: string;
  age?: number;       // 可选属性
  onFollow: (id: string) => void;
}

function UserCard({ name, age, onFollow }: UserCardProps) {
  // ...
}

Props 的只读约束与纯函数思维

将 Props 视为只读不仅是规则,更是一种思维方式:把组件当作纯函数。纯函数不会修改输入值,且同样的输入永远得到同样的输出。这种思维让你的组件行为完全可预测:

function sum(a, b) {
  return a + b;
}
// sum(1, 2) 永远返回 3,并且不会修改 a 和 b

function UserName({ name }) {
  return <span>{name}</span>;
}
// 给定相同的 name,总是渲染相同的 <span>,并且不会修改 name

理解并遵守这一约束后,你的组件将更容易测试、调试和复用,因为任何时刻你都可以根据传入的 Props 准确推断组件的外观和行为,而不必担心内部有什么“小动作”改变了这些数据。