react新官方文档学习,描述UI

179 阅读14分钟

描述UI

当你使用 react 开发一段时间后,你会发现,对于前端来说,工作内容,就是把数据按照 UI 给定的设计稿通过代码的方法描述出来,那么在这里,处理数据(得到能够渲染到页面的数据)和 展示数据 是前端开发两个重中之重的基本功。

对于我来说,我喜欢在拿到 UI 稿后,先把 HTML 骨架搭建好,也就是先实现描述 UI 这一步,然后再去获取数据,处理交互,控制数据流。也就是由易到难进行开发,接下来就一起看看官方文档如何教初学者描述 UI 的吧!


在接下来,我们会探讨如下问题

  1. 如何编写第一个 React 组件
  2. 何时以及如何创建多组件文件
  3. 如何使用 JSX 向 JavaScript 添加标记
  4. 如何在 JSX 中使用花括号来访问组件中的 JavaScript 功能
  5. 如何用props配置组件
  6. 如何有条件地呈现组件
  7. 如何一次渲染多个组件
  8. 如何通过保持组件的纯净来避免混淆 bug

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

你的第一个组件

重要程度:🌈🌈🌈🌈

先说重点,react 组件,不仅仅是一种代码组织方式,更是一种 react 编程思维

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

// app.js
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>
  );
}

你会在页面看到:

image-20230701221658409

1. 组件是什么

组件是:UI构建块

在前端,HTML让我们可以使用内置的标签集(如 <h1><li> )创建丰富的结构化文档。如:

<article>
  <h1>My First Component</h1>
  <ol>
    <li>Components: UI Building Blocks</li>
    <li>Defining a Component</li>
    <li>Using a Component</li>
  </ol>
</article>

这个标记代表这篇文章 <article> ,它的标题 <h1> ,以及一个(缩写)目录作为有序列表 <ol> 。像这样的标记,结合用于样式的 CSS 和用于交互性的 JavaScript,构成了 Web 上每个侧边栏、头像、模态框、下拉菜单等 UI 元素的基础。但是我想要复用 这个 article 组件,要怎么办呢?现在我们可以通过 react 来实现这个文章组件的复用

React允许您将标记、CSS和 JavaScript 组合成自定义的“组件”,用于您的应用程序的可重用UI元素。您在上面看到的目录代码可以转换为一个 <TableOfContents /> 组件,您可以在每个页面上呈现。在底层,它仍然使用相同的HTML标签,如 <article><h1> 等。

随着项目的发展,您会注意到许多设计可以通过重用您已经编写的组件来组合,从而加快开发速度。我们上面的目录可以添加到任何屏幕上,使用 <TableOfContents /> !您甚至可以使用React开源社区共享的成千上万个组件来快速启动项目,例如Chakra UI和Material UI。这个在你使用 ant design 组件库的时候最为明显,它封装了一些通用的组件库,我们仅仅按照官方文档的要求使用即可,不需要操心任何事情

2. 组件在React应用中扮演的角色是什么

在 react 应用中,组件就像是构建应用的 “砖块”,我们可以通过不同的“砖块”(组件),快速搭建我们 react ”房子“(应用),

3. 如何编写你的第一个React组件

React组件是一个JavaScript函数,这个函数返回一个 JSX 标记,可以渲染在页面上,当然,我们可以在函数中写一个这个组件的通用逻辑,例如:如何处理交互,创建一个新的组件,你应该做下面几个事情

  1. 导出函数
  2. 定义函数
  3. 添加标记

举个例子

export default function Profile() { // 使用 export default 导出函数 Profile 定义函数
  return ( // return一个只有一个跟标签的 html 集合,来添加标记
    <section>
      <Title>124</Title>
        <img
        src="https://i.imgur.com/MK3eW3As.jpg"
        alt="Katherine Johnson"
        />
    </section>
  );
}

4. 深入探索

您的React应用程序从一个“根”组件开始。通常,在启动新项目时会自动创建它。例如,如果您使用 CodeSandboxCreate React App,根组件在 src/App.js 中定义。如果您使用Next.js框架,则根组件在 pages/index.js 中定义。在这些示例中,您已经导出了根组件。细心的同学发现,react 创建的应用就是一个单文件应用(它仅仅有一个HTML文件),它的所有内容都在根组件中,都绑定在 id 为 #app 的根元素上,它里面包含了所有的子组件

大多数 React 应用程序都使用组件。这意味着您不仅会将组件用于可重用的部分,例如按钮,还会将其用于更大的部分,例如侧边栏、列表,甚至是完整的页面!组件是一种方便的方式来组织 UI 代码和标记,即使其中一些组件只使用一次。

基于React的框架将这一步进一步。它们不再使用空的 HTML 文件并让 React 通过 JavaScript “接管”页面的管理,而是还会自动从 React 组件中生成 HTML 。这使得您的应用在 JavaScript 代码加载之前就能显示一些内容。

然而,许多网站仅使用 React 来为现有的 HTML 页面添加交互性。它们有许多根组件,而不是一个用于整个页面。您可以根据需要使用多少或少量的 React。也就是说,你可以在你的项目指定地方使用 react

⭕️注意:

  1. 没有括号, return 之后的任何代码都将被忽略!
  1. 大小写的区别, section 小写,react 知道这是一个 HTML 标签,Title 大写 react 也就知道这是一个 React 组件
  2. 每一个组件,都应该是一个单文件,不可以在一个组件中,再声明另一个组件,这样会产生很多问题,例如:作用域混乱
// 组件可以渲染其他组件,但是你绝不能嵌套它们的定义:
// ❌
export default function Gallery() {
  // 🔴 Never define a component inside another component!
  function Profile() {
    // ...
  }
  // ...
}
// ✅ 但是更加推荐,一个组件,就放在一个文件中
export default function Gallery() {
  // ...
}
​
// ✅ Declare components at the top level
function Profile() {
  // ...
}

最后总结以下关键点

  • React 允许您创建组件,可重复使用的应用程序UI元素。

  • 在 React 应用中,每个 UI 都是一个组件。

  • React 组件是常规的 JavaScript 函数,但是:

    • 他们的名字总是以大写字母开头。
    • 它们返回 JSX 标记。

导入和导出组件

重要程度:🌈🌈🌈🌈

当我们一个项目,组件越来越多时候,把每个组件抽离为一个单文件,是有利于代码维护和组件复用,所以我们使用导入导出来实现组件的复用

您可以在一个文件中声明多个组件,但这里的缺点是组件太多可能会很难导航(因为一个文件代码太多会很乱)。要解决此问题,可以将组件导出到其他的文件中,然后从另一个文件导入该组件

// 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>
  );
}

这里我们通过 import 和 export 的形式,实现了一个组件一个文件,在复杂组件的情况,逻辑依然清晰明了

1. 根组件文件是什么

当前位于根组件文件中,例如在此示例中命名为 App.js 。在 Create React App 中,您的应用程序位于 src/App.js 。根据您的设置,您的根组件可能位于另一个文件中。如果您使用基于文件的路由的框架,例如Next.js,每个页面的根组件将不同。

2. 如何导入和导出一个组件

当我们想要根文件不放任何组件逻辑,我们就需要把根组件都移出,这样我们就需要 import 和 export ,我们应该这么做

  1. 创建一个新的JS文件来放置组件。
  2. export 从该文件中导出您的函数组件(使用默认导出或命名导出)。
  3. import 将其导入到将使用该组件的文件中(使用相应的默认导入或命名导出技术)。

3. 何时使用默认和命名的导入和导出

⭕️注意:这里导出,我们即可使用 export default 这样默认导出(这里就只能有一个 export default ),也可以 export 一个变量(这里可以有多个 export ),这里是 JavaScript 的 ES6 modules 具体详情可点击:Module 语法

image-20230702134216899

⭕️注意:导出组件的方式决定了你必须如何导入它。如果你尝试以相同的方式导入默认导出,你将会收到一个错误!这个图表可以帮助你跟踪如果文件只导出一个组件,人们通常使用默认导出;如果文件导出多个组件和值,人们通常使用命名导出。无论你偏好哪种编码风格,都要给你的组件函数和包含它们的文件赋予有意义的名称。不推荐使用没有名称的组件,例如 export default () => {} ,因为这会增加调试的难度。

4. 如何从一个文件中导入和导出多个组件

在一个文件中写多个组件,然后导出对象的格式,导出多个对象的key的value就是我们的组件

5. 如何将组件拆分为多个文件

也就是把一个组件再拆分为多个组件

最后总结一下关键点

  1. 根组件就是 react 项目的入口文件下的组件,例如:app.js 中导出的组件
  2. 通过导入导出组件来实现组件的复用
  3. 可以使用默认导出和命名导出,当只需要导出一个组件的时候,使用默认,导出多个的时候,使用命名导出

使用 JSX 编写标记

重要程度:🌈🌈🌈🌈🌈

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

如果我们将现有的HTML标记粘贴到React组件中,它并不总是有效,例如:当你 return 多个跟元素,它就会报错,因为 JSX 语法规定跟组件只能有一个,原因,我在上一篇写 React 初级开发常见错误有写

⭕️注意: JSX和 React 是两个独立的东西。它们经常一起使用,但你也可以独立使用它们。JSX 是一种语法扩展,而 React 是一个 JavaScript 库。

JSX的规则

  1. 返回一个根元素,如果需要返回多个元素,请使用 <></> 将其包裹起来
  2. 关闭所有标签,也就是任何标签都应该是关闭的 例如 <img />
  3. 骆驼命名法几乎所有的东西 例如:className 由于历史原因, aria-*data-* 属性在 HTML 中以破折号的形式书写。

总结一下:

  1. React 组件将渲染逻辑与标记组合在一起,因为它们是相关的。
  2. JSX 与 HTML 类似,但有一些区别。如果需要,您可以使用转换器。
  3. 错误消息通常会指导您修复标记。

JSX中带花括号的 JavaScript

重要程度:🌈🌈🌈🌈

它就像是给HTML 赋予了超能力,让 HTML 可以动态展示信息,

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

  1. 传递带引号的字符串,例如:给 img 标签一个动态图片地址 <img src={picture} /> ,这里picture 就是img的地址
  2. 使用花括号:进入JavaScript世界的窗口,例如:我们如果想要在HTML中写一个三元表达式,我们就可以使用{ } ,其中任何 JavaScript 表达式都可以放在花括号中,包括函数调用,例如:
// 这里 name就是一个变量,渲染到页面上就是:Gregorio Y. Zara's To Do List
export default function TodoList() {
  const name = 'Gregorio Y. Zara';
  return (
    <h1>{name}'s To Do List</h1>
  );
}
  1. 只能在这两个地方使用 花括号,1. 作为JSX标签内的文本,如上, 2. 作为紧跟在 = 标记后的属性
  2. 使用“双大括号”:在JSX中使用CSS和其他对象,例如 CSS 的style={{ backgroundColor: 'black', color: 'pink' }} 和 属性的 person={{ name: "Hedy Lamarr", inventions: 5 }}
  3. 将多个表达式移入一个对象中,并在JSX中使用花括号引用它们,例如:
// 这里就是在花括号中使用 person 对象,这样也是可以的
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>
  );
}

将props传递给组件

重要程度:🌈🌈🌈🌈

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

详情请看官方文档:react.dev/learn/passi…

条件渲染

重要程度:🌈🌈🌈🌈

您的组件通常需要根据不同的条件显示不同的内容。在React中,您可以使用JavaScript语法(如 if 语句、 &&? : 运算符)有条件地渲染JSX。在本例中,JavaScript && 运算符用于有条件地呈现复选标记:

function Item({ name, isPacked }) {
    const [isShowLast, setIsShowLast] =  useState(false)
  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"
        />
        {
         isShowLast ? <Item
          isPacked={false}
            name="Photo of Tam"
            />: <></>
          }
      </ul>
    </section>
  );
}
​

详细请看:react.dev/learn/condi…

渲染列表

重要程度:🌈🌈🌈🌈

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

对于每个数组项,需要指定一个 key (这个是非常重要且必须的)。通常,您会希望使用数据库中的ID作为 key 。Keys让React跟踪每个项目在列表中的位置,即使列表发生了变化。

详细请看:react.dev/learn/rende…

保持 react 组件为纯函数

一些JavaScript函数是纯函数。对于纯函数,它有以下特征:

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

通过严格地只将组件编写为纯函数,您可以在代码库增长时避免整个类的令人困惑的错误和不可预测的行为。这样在遇到 bug 的时候也很好排查问题出现在哪里,这里官方的例子非常的经典

// 非纯函数
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 />
    </>
  );
}

你会看到这个结果:

image-20230701225325648

我们看到 同样的<Cup /> 组件,但是渲染的结果却不相同了,这就是因为它不是一个纯函数导致的,我们可以这样写

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} />
    </>
  );
}

image-20230701225443661

就可以得到这个结果,这样才是我们想要的效果

详细请看:react.dev/learn/keepi…

如果你都看到这里了,有几个问题考考你

  1. 在 JSX 中0 && 1 渲染出来的是什么
  2. React 子组件如何接收父组件使用该组件 在标签包含的内容,例如:<Tag>123</Tag> 子组件如何获取这个 123
  3. 当我们在 return 中 使用 map 遍历的时候,为什么需要 key
  4. 什么是纯函数?如何保持组件为纯函数?为什么组件为纯函数是一个好事?

这些仅仅是对这些问题的简单总结,详细的回答,还需要我们继续看官方文档更详细的对应模块内容,希望每一个 React 开发者都看一下 dan 大神的新官方文档,真的很不错,通俗易懂