第十篇 描述UI-序

描述UI

React 是一个用于呈现用户界面 (UI) 的 JavaScript 库。 UI 由按钮、文本和图像等小单元构建而成。 React 允许您将它们组合成可重用、可嵌套的组件。 从网站到手机应用程序,屏幕上的一切都可以分解成组件。 在本章中,您将学习创建、自定义和有条件地显示 React 组件。

本章内容预告

  • 如何编写你的第一个 React 组件
  • 何时以及如何创建多组件文件
  • 如何使用 JSX 向 JavaScript 添加标记
  • 如何在 JSX 中使用花括号从组件中访问 JavaScript 功能
  • 如何使用 props 配置组件
  • 如何有条件地渲染组件
  • 如何一次渲染多个组件
  • 如何通过保持组件纯净来避免混淆错误

你的第一个组件

React 应用程序是由称为组件的独立 UI 部分构建的。 React 组件是一个 JavaScript 函数,您可以在其中添加标记。 组件可以小到一个按钮,也可以大到整个页面。 这是一个 Gallery 组件渲染三个 Profile 组件:

function Profile() {
  return (
    <img
      src="https://i.imgur.com/MK3eW3As.jpg"
      alt="Katherine Johnson"
    />
  );
}

export default function Gallery() {
  return (
    <section>
      <h1>Amazing scientists</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}

准备好学习这个主题了吗?

阅读你的第一个组件以了解如何声明和使用 React 组件。

导入和导出组件

您可以在一个文件中声明多个组件,但大文件可能难以导航。 要解决这个问题,您可以将一个组件导出到它自己的文件中,然后从另一个文件中导入该组件:
Profile.js

export default function Profile() {
  return (
    <img
      src="https://i.imgur.com/QIrZWGIs.jpg"
      alt="Alan L. Hart"
    />
  );
}

Gallery.js

import Profile from './Profile.js';

export default function Gallery() {
  return (
    <section>
      <h1>Amazing scientists</h1>
      <Profile />
      <Profile />
      <Profile />
    </section>
  );
}

准备好学习这个主题了吗?

阅读导入和导出组件以了解如何将组件拆分到它们自己的文件中。

使用JSX写标记

每个 React 组件都是一个 JavaScript 函数,其中可能包含 React 呈现到浏览器中的一些标记。 React 组件使用称为 JSX 的扩展语法来表示该标记。 JSX 看起来很像 HTML,但更严格一些,并且可以显示动态信息。

如果我们将现有的 HTML 标记粘贴到 React 组件中,它并不总是有效:

export default function TodoList() {
  return (
    // This doesn't quite work!
    <h1>Hedy Lamarr's Todos</h1>
    <img
      src="https://i.imgur.com/yXOvdOSs.jpg"
      alt="Hedy Lamarr"
      class="photo"
    >
    <ul>
      <li>Invent new traffic lights
      <li>Rehearse a movie scene
      <li>Improve spectrum technology
    </ul>
  );
}
Error
/App.js: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...</>? (5:4)

  3 |     // This doesn't quite work!
  4 |     <h1>Hedy Lamarr's Todos</h1>
> 5 |     <img
    |     ^
  6 |       src="https://i.imgur.com/yXOvdOSs.jpg"
  7 |       alt="Hedy Lamarr"
  8 |       class="photo"

如果您有这样的现有 HTML,您可以使用转换器修复它:

export default function TodoList() {
  return (
    <>
      <h1>Hedy Lamarr's Todos</h1>
      <img
        src="https://i.imgur.com/yXOvdOSs.jpg"
        alt="Hedy Lamarr"
        className="photo"
      />
      <ul>
        <li>Invent new traffic lights</li>
        <li>Rehearse a movie scene</li>
        <li>Improve spectrum technology</li>
      </ul>
    </>
  );
}

准备好学习这个主题了吗?

阅读使用 JSX 编写标记以了解如何编写有效的 JSX。

JSX 中带有花括号的 JavaScript

JSX 允许您在 JavaScript 文件中编写类似 HTML 的标记,将呈现逻辑和内容保持在同一位置。 有时您会希望在该标记内添加一些 JavaScript 逻辑或引用动态属性。 在这种情况下,您可以在 JSX 中使用大括号为 JavaScript “打开一个窗口”:

const person = {
  name: 'Gregorio Y. Zara',
  theme: {
    backgroundColor: 'black',
    color: 'pink'
  }
};

export default function TodoList() {
  return (
    <div style={person.theme}>
      <h1>{person.name}'s Todos</h1>
      <img
        className="avatar"
        src="https://i.imgur.com/7vQD0fPs.jpg"
        alt="Gregorio Y. Zara"
      />
      <ul>
        <li>Improve the videophone</li>
        <li>Prepare aeronautics lectures</li>
        <li>Work on the alcohol-fuelled engine</li>
      </ul>
    </div>
  );
}

准备好学习这个主题了吗?

阅读JSX 中带有花括号的 JavaScript了解如何从 JSX 访问 JavaScript 数据。

将 props 传递给组件

React 组件使用 props 相互通信。 每个父组件都可以通过给它们 props 将一些信息传递给它的子组件。 Props 可能会让你想起 HTML 属性,但你可以通过它们传递任何 JavaScript 值,包括对象、数组、函数,甚至 JSX!
App.js

import { getImageUrl } from './utils.js'

export default function Profile() {
  return (
    <Card>
      <Avatar
        size={100}
        person={{
          name: 'Katsuko Saruhashi',
          imageId: 'YfeOqp2'
        }}
      />
    </Card>
  );
}

function Avatar({ person, size }) {
  return (
    <img
      className="avatar"
      src={getImageUrl(person)}
      alt={person.name}
      width={size}
      height={size}
    />
  );
}

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

utils.js

export function getImageUrl(person, size = 's') {
  return (
    'https://i.imgur.com/' +
    person.imageId +
    size +
    '.jpg'
  );
}

准备好学习这个主题了吗?

阅读将props传递给组件以了解如何传递和读取props。

条件渲染

您的组件通常需要根据不同的条件显示不同的内容。 在 React 中,您可以使用 if 语句、&& 和 ? : 等JavaScript运算符语法有条件地渲染 JSX。

在此示例中,JavaScript && 运算符用于有条件地呈现复选标记:

function Item({ name, isPacked }) {
  return (
    <li className="item">
      {name} {isPacked && '✔'}
    </li>
  );
}

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride's Packing List</h1>
      <ul>
        <Item
          isPacked={true}
          name="Space suit"
        />
        <Item
          isPacked={true}
          name="Helmet with a golden leaf"
        />
        <Item
          isPacked={false}
          name="Photo of Tam"
        />
      </ul>
    </section>
  );
}

准备好学习这个主题了吗?

阅读条件渲染以了解有条件地渲染内容的不同方式。

渲染列表

您通常希望显示数据集合中的多个相似组件。 您可以将 JavaScript 的 filter() 和 map() 与 React 结合使用,以过滤数据数组并将其转换为组件数组。

对于每个数组项,您需要指定一个key。 通常,您会希望使用数据库中的 ID 作为key。 key让 React 跟踪每个项目在列表中的位置,即使列表发生变化。
App.js

import { people } from './data.js';
import { getImageUrl } from './utils.js';

export default function List() {
  const listItems = people.map(person =>
    <li key={person.id}>
      <img
        src={getImageUrl(person)}
        alt={person.name}
      />
      <p>
        <b>{person.name}:</b>
        {' ' + person.profession + ' '}
        known for {person.accomplishment}
      </p>
    </li>
  );
  return (
    <article>
      <h1>Scientists</h1>
      <ul>{listItems}</ul>
    </article>
  );
}

data.js

export const people = [{
  id: 0,
  name: 'Creola Katherine Johnson',
  profession: 'mathematician',
  accomplishment: 'spaceflight calculations',
  imageId: 'MK3eW3A'
}, {
  id: 1,
  name: 'Mario José Molina-Pasquel Henríquez',
  profession: 'chemist',
  accomplishment: 'discovery of Arctic ozone hole',
  imageId: 'mynHUSa'
}, {
  id: 2,
  name: 'Mohammad Abdus Salam',
  profession: 'physicist',
  accomplishment: 'electromagnetism theory',
  imageId: 'bE7W1ji'
}, {
  id: 3,
  name: 'Percy Lavon Julian',
  profession: 'chemist',
  accomplishment: 'pioneering cortisone drugs, steroids and birth control pills',
  imageId: 'IOjWm71'
}, {
  id: 4,
  name: 'Subrahmanyan Chandrasekhar',
  profession: 'astrophysicist',
  accomplishment: 'white dwarf star mass calculations',
  imageId: 'lrWQx8l'
}];

utils.js

export function getImageUrl(person) {
  return (
    'https://i.imgur.com/' +
    person.imageId +
    's.jpg'
  );
}

准备好学习这个主题了吗?

阅读渲染列表以了解如何渲染组件列表以及如何选择key。

保持组件纯净

一些 JavaScript 函数是纯函数。 纯函数:

  • 管好自己的事。 它不会更改调用之前存在的任何对象或变量。
  • 相同的输入,相同的输出。 给定相同的输入,纯函数应该总是返回相同的结果。

通过严格地将您的组件编写为纯函数,您可以在代码库增长时避免一整类令人困惑的错误和不可预测的行为。 这是一个不纯洁的组件的例子:

let guest = 0;

function Cup() {
  // Bad: changing a preexisting variable!
  guest = guest + 1;
  return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaSet() {
  return (
    <>
      <Cup />
      <Cup />
      <Cup />
    </>
  );
}

你可以通过传递一个 prop 而不是修改一个预先存在的变量来使这个组件变得纯粹:

function Cup({ guest }) {
  return <h2>Tea cup for guest #{guest}</h2>;
}

export default function TeaSet() {
  return (
    <>
      <Cup guest={1} />
      <Cup guest={2} />
      <Cup guest={3} />
    </>
  );
}

准备好学习这个主题了吗?

阅读保持组件纯净以了解如何将组件编写为纯粹的、可预测的函数。

下一步是什么?

转到您的第一个组件开始逐页阅读本章!
或者,如果您已经熟悉这些主题,为什么不阅读有关添加交互性的内容呢?

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,869评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,716评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,223评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,047评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,089评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,839评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,516评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,410评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,920评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,052评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,179评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,868评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,522评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,070评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,186评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,487评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,162评论 2 356

推荐阅读更多精彩内容