Skip to content

React Props 与数据渲染

前端框架 Props ES6

一、React Props(属性)

1.1 什么是 Props

Props = Properties = 传递给组件的 自定义属性

类比 HTML 属性:

html
<!-- HTML — 预定义属性 -->
<input id="fName" placeholder="First Name" value="Angela" />

<!-- React — 自定义属性(Props) -->
<Card name="Beyoncé" img="url..." tel="123456" email="b@mail.com" />

1.2 传递 Props

jsx
// 使用组件时,像 HTML 属性一样传递数据
<Card
  name="Beyoncé"
  img="https://example.com/beyonce.jpg"
  tel="+123 456 789"
  email="b@email.com"
/>

1.3 接收 Props

组件函数的 第一个参数 就是 props 对象:

javascript
function Card(props) {
  // props = {
  //   name: "Beyoncé",
  //   img: "https://example.com/beyonce.jpg",
  //   tel: "+123 456 789",
  //   email: "b@email.com"
  // }

  return (
    <div className="card">
      <h2>{props.name}</h2>
      <img src={props.img} alt="avatar" />
      <p>{props.tel}</p>
      <p>{props.email}</p>
    </div>
  );
}

1.4 组件复用

Props 的核心价值 = 一个组件,多组数据

jsx
<Card name="Beyoncé" img="..." tel="123" email="b@mail.com" />
<Card name="Jack"    img="..." tel="456" email="j@mail.com" />
<Card name="Chuck"   img="..." tel="789" email="c@mail.com" />

每个 <Card /> 使用相同的组件代码,但渲染不同的数据。

1.5 Props 的关键规则

重要

HTML 属性(如 classNamestyleonClick)只能用在 HTML 元素 上,不能用在自定义组件上。

jsx
// ❌ 自定义组件上的 className 会被当作 prop,不会应用样式
<Card className="my-style" />

// ✅ className 必须放在 HTML 元素上
function Card(props) {
  return <div className="my-style">...</div>;
}

二、用数据数组渲染组件

2.1 数据与 UI 分离

最佳实践:将数据存储在单独的文件中:

javascript
// contacts.js
const contacts = [
  {
    id: 1,
    name: "Beyoncé",
    imgURL: "https://example.com/beyonce.jpg",
    phone: "+123 456 789",
    email: "b@email.com"
  },
  {
    id: 2,
    name: "Jack Bauer",
    imgURL: "https://example.com/jack.jpg",
    phone: "+987 654 321",
    email: "j@email.com"
  }
];

export default contacts;

2.2 使用 map 渲染列表

jsx
import contacts from "./contacts";

function App() {
  return (
    <div>
      <h1>My Contacts</h1>
      {contacts.map(contact => (
        <Card
          key={contact.id}
          name={contact.name}
          img={contact.imgURL}
          tel={contact.phone}
          email={contact.email}
        />
      ))}
    </div>
  );
}

key 属性

React 使用 key 来追踪列表中每个元素的身份。key 必须是 唯一 的(通常用 id)。

jsx
// ❌ 没有 key → 控制台警告
{items.map(item => <Card name={item.name} />)}

// ✅ 有 key → React 高效更新
{items.map(item => <Card key={item.id} name={item.name} />)}

三、ES6 核心特性

3.1 箭头函数(Arrow Functions)

javascript
// 传统函数
function double(x) {
  return x * 2;
}

// 箭头函数
const double = (x) => {
  return x * 2;
};

// 单表达式 — 隐式返回(省略 return 和花括号)
const double = x => x * 2;

在 map 中的应用:

javascript
const numbers = [3, 56, 2, 48, 5];

// 传统写法
const doubled = numbers.map(function(num) {
  return num * 2;
});

// 箭头函数简写
const doubled = numbers.map(num => num * 2);
// → [6, 112, 4, 96, 10]

3.2 map — 映射转换

对数组的每个元素执行操作,返回 新数组

javascript
const numbers = [3, 56, 2, 48, 5];

const doubled = numbers.map(x => x * 2);
// → [6, 112, 4, 96, 10]

const strings = numbers.map(x => x.toString() + "!!");
// → ["3!!", "56!!", "2!!", "48!!", "5!!"]

React 中的 map — 渲染组件列表:

jsx
{emojis.map(emoji => (
  <Entry
    key={emoji.id}
    emoji={emoji.symbol}
    name={emoji.name}
    meaning={emoji.meaning}
  />
))}

3.3 filter — 过滤筛选

返回满足条件的元素组成的 新数组

javascript
const numbers = [3, 56, 2, 48, 5];

const big = numbers.filter(x => x > 10);
// → [56, 48]

const small = numbers.filter(x => x <= 10);
// → [3, 2, 5]

3.4 reduce — 累计计算

将数组 归约 为单个值:

javascript
const numbers = [3, 56, 2, 48, 5];

const sum = numbers.reduce((accumulator, current) => {
  return accumulator + current;
});
// 运算过程:
// 第1次:accumulator=3,  current=56 → 59
// 第2次:accumulator=59, current=2  → 61
// 第3次:accumulator=61, current=48 → 109
// 第4次:accumulator=109,current=5  → 114
// → 114

3.5 find — 查找第一个匹配

返回 第一个 满足条件的元素(非数组):

javascript
const numbers = [3, 56, 2, 48, 5];

const found = numbers.find(x => x > 10);
// → 56(第一个大于 10 的元素)

3.6 findIndex — 查找索引

返回第一个满足条件的元素的 索引

javascript
const numbers = [3, 56, 2, 48, 5];

const index = numbers.findIndex(x => x > 10);
// → 1(56 的索引位置)

3.7 数组方法对比

方法返回值用途
map新数组(等长)转换每个元素
filter新数组(≤原长)筛选元素
reduce单个值累计计算
find单个元素找到第一个匹配
findIndex数字(索引)找到第一个匹配的位置
forEachundefined遍历(无返回)

四、条件渲染

4.1 三元运算符(Ternary Operator)

jsx
// 语法:condition ? expressionIfTrue : expressionIfFalse

{isLoggedIn ? <h1>Hello!</h1> : <Login />}

实际应用:

javascript
const currentTime = new Date().getHours();

{currentTime < 12
  ? <h1>Good Morning</h1>
  : <h1>Good Afternoon</h1>
}

4.2 && 运算符(短路求值)

当只需要在条件为 true 时渲染,没有 else 分支:

jsx
// 语法:condition && expression
// condition 为 true → 渲染 expression
// condition 为 false → 什么都不渲染

{unreadMessages.length > 0 &&
  <h2>You have {unreadMessages.length} unread messages.</h2>
}

原理:

javascript
true && "Hello"   // → "Hello"(返回右边)
false && "Hello"  // → false(返回左边,React 不渲染 false)

4.3 条件渲染模式对比

模式适用场景示例
三元 ? :两个分支(if/else){isLoggedIn ? <Home /> : <Login />}
&&只有 if(无 else){showWarning && <Warning />}
提前 return组件级条件if (!data) return <Loading />;

五、ES6 解构赋值(Destructuring)

5.1 对象解构

javascript
const person = { name: "Angela", age: 26, hobby: "cooking" };

// 传统方式
const name = person.name;
const age = person.age;

// ES6 解构
const { name, age, hobby } = person;
// name → "Angela", age → 26, hobby → "cooking"

Props 解构:

javascript
// 传统方式
function Card(props) {
  return <h2>{props.name}</h2>;
}

// 解构方式 ⭐
function Card({ name, img, tel, email }) {
  return (
    <div>
      <h2>{name}</h2>
      <img src={img} alt="avatar" />
      <p>{tel}</p>
      <p>{email}</p>
    </div>
  );
}

5.2 数组解构

javascript
const [r, g, b] = [255, 128, 64];
// r → 255, g → 128, b → 64

// 常见于 React Hooks
const [count, setCount] = useState(0);

5.3 默认值

javascript
const { name = "Anonymous", age = 0 } = {};
// name → "Anonymous", age → 0

const [first = 1, second = 2] = [10];
// first → 10, second → 2

六、ES6 展开运算符(Spread Operator)

6.1 数组展开

javascript
const citrus = ["Lime", "Lemon", "Orange"];
const fruits = ["Apple", ...citrus, "Banana"];
// → ["Apple", "Lime", "Lemon", "Orange", "Banana"]

// 合并数组
const all = [...arr1, ...arr2];

6.2 对象展开

javascript
const fullName = { fName: "James", lName: "Bond" };
const user = { ...fullName, id: 1, email: "007@mi6.com" };
// → { fName: "James", lName: "Bond", id: 1, email: "007@mi6.com" }

6.3 在 React 中的应用

jsx
const contact = {
  name: "Beyoncé",
  img: "https://example.com/beyonce.jpg",
  tel: "+123 456 789",
  email: "b@email.com"
};

// 传统方式
<Card name={contact.name} img={contact.img} tel={contact.tel} email={contact.email} />

// 展开运算符 ⭐
<Card {...contact} />
// 等同于将 contact 对象的所有属性作为 props 传入

添加新状态(不可变更新):

javascript
const [items, setItems] = useState([]);

// ❌ 直接修改
items.push(newItem);   // 不会触发重新渲染!

// ✅ 展开 + 新元素
setItems(prev => [...prev, newItem]);

七、Keeper App 项目结构

7.1 组件树

App
├── Header          — 应用标题
├── Note            — 笔记卡片(可复用)
├── Note
├── ...
├── CreateArea      — 创建新笔记的表单
└── Footer          — 版权信息

7.2 文件结构

src/
├── index.js                    # 入口
└── components/
    ├── App.jsx                 # 根组件
    ├── Header.jsx              # 头部
    ├── Footer.jsx              # 页脚(动态年份)
    ├── Note.jsx                # 笔记卡片
    └── CreateArea.jsx          # 创建区域

7.3 组件示例

jsx
// Header.jsx
function Header() {
  return (
    <header>
      <h1>Keeper</h1>
    </header>
  );
}

// Footer.jsx
function Footer() {
  const year = new Date().getFullYear();
  return (
    <footer>
      <p>Copyright ⓒ {year}</p>
    </footer>
  );
}

// Note.jsx
function Note({ title, content }) {
  return (
    <div className="note">
      <h1>{title}</h1>
      <p>{content}</p>
    </div>
  );
}

八、速查表

概念语法
Props 传递<Card name="Angela" age={26} />
Props 接收function Card(props)function Card({ name, age })
map 渲染{items.map(item => <Component key={item.id} {...item} />)}
filterarr.filter(x => x > 10)
reducearr.reduce((acc, cur) => acc + cur)
findarr.find(x => x > 10)
findIndexarr.findIndex(x => x > 10)
三元渲染{condition ? <A /> : <B />}
&& 渲染{condition && <A />}
对象解构const { name, age } = props
数组解构const [a, b] = [1, 2]
展开 props<Card {...contactObj} />
展开合并[...oldArr, newItem]

← 返回 Web 开发研究