【2024官方文档版】React-描述IU

系列文章目录

一、快速入门【基础】
二、描述IU


二、描述IU

1.第一个组件

1.1 组件是什么?

React 组件是一段可以 使用标签进行扩展 的 JavaScript 函数。
组件名称首字母必须大写!!!否则不能运行的嗷
如下示例就是一个简单的组件:

function MyButton() {
    return (
        <>
            <button> i an a button</button>
        </>
    );
}

就像使用 HTML 标签一样,你可以组合、排序和嵌套组件来绘制整个页面.

	<PageLayout>
  <NavigationHeader>
    <SearchBar />
    <Link to="/docs">文档</Link>
  </NavigationHeader>
  <Sidebar />
  <PageContent>
    <TableOfContents />
    <DocumentationText />
  </PageContent>
</PageLayout>

随着项目的进行,你会发现有很多的组件都可以复用,提高代码的利用率,加快开发的进度
React开源社区也提供了很多的组件可以使用哦

1.2 构建组件的方法

  • 第一步: 导出组件 使用export default
    使用在一个文件中的主要的函数上,这个函数之后在别的文件中可以引用
  • 第二步: 定义函数 function FunctionName(){}
  • 第三步: 添加标签,这个标签写的像HTML,其实是JSX,这个语法允许将标签嵌入到js代码中,注意如果return的代码有多行,要括号包裹.
    在这里插入图片描述
  • MyButton组件就可以在其他组件使用了

注意组件必须首字母大写!!!HTML标签要小写!!!
这样浏览器才能识别出来哪个是组件哪个是标签

export default function MyApp() {
    return (
        <div>
            <h1>welcome to react</h1>
            <MyButton />
            <MyButton />
        </div>
    )
}

1.3嵌套和组织组件

组件可以一次定义,多次使用
使用组件我们还需要注意:

  • 不要在组件中定义组件!!会导致bug的产生
  • 如果子组件需要使用父组件的数据,我们可以通过使用prop来传递数据

1.4课后作业

  • 修复它
    在这里插入图片描述

  • 找出错误
    在这里插入图片描述

  • 写个组件
    在这里插入图片描述
    答案:1.未导出 2.未首字母大写 3.略

1.5 小结:

React中,每个ui模块都是一个组件
React 是常规的 JavaScript 函数,除了他们的名字首字母大写!!!,返回的是JSX标签


2.组件的导入导出

2.1根组件文件

在第一个组件,创建了MyButton组件,渲染在了MyApp中,我们都定义在了根组件App.js

2.2 导入导出文件

为了使组件更加模块化, 而且可以在其他文件中复用,我们可以对于组件进行下列步骤的拆分:

  • 第一步:创建一个新的js文件存放该组件
  • 第二步:导出export文件中的函数组件
  • 第三步:在需要用到组件的文件中导入import组件
    -比如这个栗子,将MyApp组件App.js中移动到MyApp.js文件中导出,再导入进App.js文件中
//MyApp.js
function MyButton() {
    return (
        <>
            <button> i an a button</button>
        </>
    );
}
export default function MyApp() {
    return (
        <div>
            <h1>welcome to react</h1>
            <MyButton />
            <MyButton />
        </div>
    )
}
//App.js
import MyApp from './MyApp.js';
export default function App(){
	return(
		<MyApp />
	)
}

引入过程中有些文件未加.js后缀,可以正常使用,加前缀更符合原生ES模块
具名导出和默认导出:
同一文件,只能有一个默认导出,但是可以有多个具名导出在这里插入图片描述


3. 使用JSX书写标签语言

JSX使JS的语法扩展,在JS代码中写类似于HTML的标签,简洁易懂
JSX 看起来和HTML很像,但它的语法更加严格并且可以动态展示信息。了解这些区别最好的方式就是将一些HTML标签转化为 JSX 标签。

3.1 将HTML转化为JSX

<h1>海蒂·拉玛的待办事项</h1>
<img 
  src="https://i.imgur.com/yXOvdOSs.jpg" 
  alt="Hedy Lamarr" 
  class="photo"
>
<ul>
    <li>发明一种新式交通信号灯
    <li>排练一个电影场景
    <li>改进频谱技术
</ul>

*JSX规则:
1.只能返回一个根元素,如果有多个元素,可以使用空标签Fragment<></>或者<div></div>包裹
2.标签必须闭合
3.大部分属性使用驼峰命名法。例如,需要用 strokeWidth 代替 stroke-width。由于 class 是一个保留字,所以在React 中需要用 className 来代替。aria-* 和 data-* 属性是以带-符号的HTML格式书写的。
4.建议使用 转化器HTMLSVG 标签转化为 JSX

现在把这些标签迁移到组件中
步骤一:先创建一个函数,将标签放进去,注意要包裹在一个父标签中
步骤二:标签都要闭合
步骤三:换成JSX的属性

最终代码如下:

export default function ToDoList() {
    return (
        <>
            <h1>海蒂·拉玛的待办事项</h1>
            <img
                src="https://i.imgur.com/yXOvdOSs.jpg"
                alt="Hedy Lamarr"
                className="photo"
            />
            <ul>
                <li>发明一种新式交通信号灯</li>
                <li>排练一个电影场景</li>
                <li>改进频谱技术</li>
            </ul>
        </>
    )
}

报错也不要担心,错误提示会指引修改成功的嘻嘻

3.2作业

  • 修复代码使它变成JSX,参照规则修改哦
export default function Bio() {
  return (
    <div class="intro">
      <h1>欢迎来到我的站点!</h1>
    </div>
    <p class="summary">
      你可以在这里了解我的想法。
      <br><br>
      <b>还有科学家们的<i>照片</b></i></p>
  );
}

答案:略


4. 在JSX中通过大括号使用JS

在标签中使用js的逻辑或者动态属性,这个时候可以使用{ }

4.1 引号传递字符串

字符串传递JSX,放在单引号/双引号
<img className="avater" src="./imgs/avater.jpg">

4.2 {} 引用js变量

上面imgsrc想动态指定,用 { } 替代 " " 来使用 JS变量
<img className="avater" src={ avater }>

src= { avatar } 这种写法会去读取 JavaScript 中 avatar 这个变量的值

也可以在HTML标签中嵌入JS变量,下面代码的 name就是

return (
    <h1>{name}'s To Do List</h1>
  );

4.3 {}引用js函数

Intl.DateTimeFormat()是 JavaScript 中用于处理日期和时间格式化的内置对象。

// 创建一个 DateTimeFormat 对象
// 'en-US' 参数指定了美国英语环境
const f = new Intl.DateTimeFormat('en-US');
// 格式化日期对象
const date = new Date('2024-04-14T12:00:00');
// f.format() 方法,该方法会将日期格式化为字符串
const formattedDate = f.format(date);

// 输出:4/14/2024
console.log(formattedDate); 

下面就是一个栗子说明如何在JSX中引入js函数
创建了一个formatDate()函数,然后在TodoList中引入这个函数。

const today = new Date();

function formatDate(date) {
  return new Intl.DateTimeFormat(
  	//汉语环境
    'zh-CN',
    { weekday: 'long' }
  ).format(date);
}

export default function TodoList() {
  return (
    <h1>To Do List for {formatDate(today)}</h1>
  );
}2

小结:

4.4 {{ }}引用js对象和CSS

对象person={{ name: "Hedy Lamarr", inventions: 5 }}
对象也需要{}包裹,JSX传递也需要{},所以双层大括号。
样式:样式多个的话也是要{}包裹的,所以也是{{}}

export default function TodoList() {
  return (
    <ul style={{
      backgroundColor: 'black',
      color: 'pink'
    }}>
    </ul>
  );
}

注意:内联 style 属性 使用驼峰命名法编写
HTML <ul style="background-color: black"> 在你的组件里应该写成 <ul style={{ backgroundColor: 'black' }}>

4.5 使用一个对象的属性

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

4.6 小结

有关JSX的知识点:

  • JSX 引号内的值会作为字符串传递给属性。
  • 大括号让你可以将JS的逻辑和变量带入到标签中
  • {{ }} 并不是什么特殊的语法:它只是包在 JSX 大括号内的JS 对象。

5. 将prop传递给组件

5.1 向组件传递props

Props 是你传递给 JSX 标签的信息。
步骤一: 将 props 传递给子组件,下面栗子传递一个对象person和数字size

export default function Profile() {
  return (
    <Avatar
      person={{ name: 'Lin Lanying', imageId: '1bX5QH6' }}
      size={100}
    />
  );
}

步骤二:子组件接收读取props。通过在 function Avatar 之后直接列出它们的名字 person, size 来读取这些props,然后使用就可以了,可以通过多种方式进行渲染。

function Avater({ person, size }) {
    return (
        <img alt="person.name" width={size} />
    )
}

注意事项:声明props时,别忘记加{ }

5.2给prop指定一个默认值

在没有指定值的情况下给 prop 一个默认值,你可以通过在参数后面写 = 和默认值来进行解构:
function Avater({ person, size=10 }) {}
默认值仅在缺少 size prop size={undefined} 时生效。

5.3 props简洁展开

当出现这种情况:
在这里插入图片描述
可以使用下面这个用法传递参数:
这会将 Profile 的所有props转发到 Avatar,而不列出每个名字。

function Profile(props) {
  return (
    <div className="card">
      <Avatar {...props} />
    </div>
  );
}

5.4 将JSX作为子组件传递

像标签嵌套一样嵌套组件
将内容嵌套在JSX标签中时,父组件将在名为 children prop中接收到该内容。

function Avater({ person, size }) {
    return (
        <img alt="person.name" width={size} />
    )
}

function Card({ children }) {
    return (
        <div>
            {children}
        </div>
    )
}

function Profile() {
    return (
        <Card>
            <Avater person={{name:'ruru',age:18}} size={100}/>
        </Card>
    )
}

5.5 props随时间的变化

一个组件可能会随着时 间的推移收到不同的 props。然而,props 是 不可变的,当组件需要改变props,父组件需要传递新的props,旧的将被回收。

5.6 小结:

  • 要读取 props,使用function xxx({ person, size })解构语法。
  • 可以指定一个默认值,如 size = 100,用于缺少 值或值为 undefinedprops
  • 可以使用 ...props JSX 展开语法转发所有props,合理使用
  • <Card><Avatar /></Card> 这样的嵌套 JSX,将被视为 Card 组件的 children prop
  • 不能改变 props。需要交互性时,可以设置 state。

6. 条件渲染

根据不同的情况显示不同的内容
可以通过使用 JSif 语句、&&? : 运算符来选择性地渲染JSX

6.1 条件返回JSX

也就是根据传进去的数据渲染页面
下面这个栗子定义一个Item组件,传进去不同的数据,渲染出的效果也是不同的

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

export default function PackingList() {
  return (
    <section>
      <h1>Sally Ride 的行李清单</h1>
      <ul>
        <Item 
          isPacked={true} 
          name="宇航服" 
        />
        <Item 
          isPacked={true} 
          name="带金箔的头盔" 
        />
        <Item 
          isPacked={false} 
          name="Tam 的照片" 
        />
      </ul>
    </section>
  );
}

在这里插入图片描述
代码中有个isPacked,可以根据这个的值,用if语句在那些满足 isPacked={true} 条件的物品旁加上一个勾选符号(✔)

...
if (isPacked) {
  return <li className="item">{name}</li>;
}
return <li className="item">{name}</li>;
...

在这里插入图片描述

6.2 返回null

当你不想渲染,但是组件必须要返回某个东西,就可以返回null

//如果组件的 isPacked 属性为 true,那么它将只返回 null。
if (isPacked) {
  return null;
}

在这里插入图片描述

6.3 三目运算符(? :)

一种紧凑型语法来实现条件判断表达式,也叫条件运算符。用法就是:
判断表达式 ?选项A : 选项B 表达式值为true则选项A,false则选项B

6.4 与运算符(&&)

仅当 isPackedtrue 时,渲染勾选符号。

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

JavaScript && 表达式 的左侧(我们的条件)为 true 时,它则返回其右侧的值(在我们的例子里是勾选符号)。但条件的结果是 false,则整个表达式会变成 false
JSX里,React 会将 false 视为一个“空值”,就像 null 或者 undefined,这样React就不会在这里进行任何渲染。
切勿将数字放在 && 左侧.!!!

6.3 冗长却灵活的if

当这些快捷方式妨碍写普通代码时,可以考虑使用 if 语句和变量。
相关代码:

function Item({ name, isPacked }) {
  let itemContent = name;
  if (isPacked) {
    itemContent = name + " ✔";
  }
  return (
    <li className="item">
      {itemContent}
    </li>
  );
}

6.4小结

  • React可以使用JS来控制分支逻辑。
  • 可以使用 if 语句来选择性地返回 JSX 表达式。
  • 可以选择性地将一些 JSX 赋值给变量,然后用大括号将其嵌入到其他 JSX 中。
  • 在 JSX 中,{cond ? <A /> : <B />} 表示 “当 cond 为真值时, 渲染 <A />,否则 <B />”。
  • 在 JSX 中,{cond && <A />} 表示 “当 cond 为真值时, 渲染 <A />,否则不进行渲染”。
  • 快捷的表达式很常见,if也可以常用。

7.渲染列表

7.1从数组中渲染数据

可以把要用到的数据存入JS对象或数组,然后用 map() filter()这样的方法来渲染出一个组件列表。

现存一个列表:

<ul>
    <li>ruru</li>
    <li>fufu</li>
    <li>shushu</li>
</ul>

步骤一:数据存到数组里
const people = ['ruru','fufu','shushu'];
步骤二:遍历people,获得一个新的JSX节点数组listItems
const listItems = people.map(person => <li>{person}</li>)
步骤三:ul标签包裹listItems并返回
return <ul> listItems </ul>;
完整代码:

const people = ['ruru', 'fufu', 'shushu'];

function List() {
    const listItems = people.map(p => <li>{p}</li>);
    return <ul>ullistItems</ul>
}

7.2对数组进行过滤

我想显示性别为‘女·’的家人,可以使用filter方法来实现。
这个方法会让数组的子项经过 “过滤器”(一个返回值为 true 或 false 的函数)的筛选,最终返回一个只包含满足条件的项的新数组。
步骤一:创建一个新数组Womens,过滤

const Women = family.filter(p => {
    p.sex === "女"
});

步骤二:map方法遍历Women数组
注意必须给数组中的每一项都指定一个 key——它可以是字符串或数字的形式,只要能唯一标识出各个数组项就行

const listItems = Women.map(p => {
    <div  key={person.id}>
        我叫{p.name},我的性别是{p.sex}
    </div>
})

步骤三:返回这个数组
return <ul>{listItems}</ul>;

注意:
1,因为箭头函数会隐式地返回位于=>之后的表达式,所以你可以省略return语句。不过,如果你的 => 后面跟了一对花括号{,那你必须使用 return 来指定返回值!假如你忘了写 return,那这个函数什么都不会返回!
2.数组的唯一标识key,首先要是唯一的,其次值不能变。

8. 保持组件纯粹

纯函数仅执行计算操作,不做其他操作
可以通过将组件按纯函数严格编写,以避免一些随着代码库的增长而出现的、令人困扰的 bug 以及不可预测的行为。

8.1纯函数:组件作为公式

纯函数的两个特征:不会更改在该函数调用前就已存在的对象或变量;输入相同,则输出相同。

比如说,y=2x,x为3时,y永远是6,函数实现如下。这个函数就是个纯函数

function double(number) {
  return 2 * number;
}

React 假设你编写的所有组件都是纯函数。
对于相同的输入,你所编写的 React 组件必须总是返回相同的 JSX

如下,当你给函数 Recipe 传入 drinkers={2} 参数时,它将返回包含 2 cups of water 的 JSX。永远如此

function Recipe({ drinkers }) {
  return (
    <ol>    
      <li>Boil {drinkers} cups of water.</li>
      <li>Add {drinkers} spoons of tea and {0.5 * drinkers} spoons of spice.</li>
      <li>Add {0.5 * drinkers} cups of milk to boil and sugar to taste.</li>
    </ol>
  );
}

export default function App() {
  return (
    <section>
      <h1>Spiced Chai Recipe</h1>
      <h2>For two</h2>
      <Recipe drinkers={2} />
      <h2>For a gathering</h2>
      <Recipe drinkers={4} />
    </section>
  );
}

一个不纯粹的栗子:
在渲染过程中,组件改变了 预先存在的 变量的值。我们将这种现象称为 突变

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

结果:
在这里插入图片描述
修复: 将guest作为 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} />
    </>
  );
}

现在你的组件就是纯粹的,因为它返回的 JSX 只依赖于 guest prop,结果:
在这里插入图片描述

9. 将UI视为树

将 UI 建模为树。将应用程序视为树有利于理解组件之间的关系以及调试性能和状态管理等。

9.1 渲染树

我们看一段代码理解一下

import FancyText from './FancyText';
import InspirationGenerator from './InspirationGenerator';
import Copyright from './Copyright';

export default function App() {
  return (
    <>
      <FancyText title text="Get Inspired App" />
      <InspirationGenerator>
        <Copyright year={2004} />
      </InspirationGenerator>
    </>
  );
}

效果:
在这里插入图片描述
结构如下:
渲染树表示 React 应用程序的单个渲染过程。
这棵树由节点组成,每个节点代表一个组件。例如,App、FancyText、Copyright 等都是我们树中的节点。
根节点是应用程序的 根组件
树中的每个箭头从父组件指向子组件。
在这里插入图片描述

9.2 模块依赖树

使用树来建模的另一个关系是应用程序的模块依赖关系
当 拆分组件 和逻辑到不同的文件中时,就创建了 JS模块,在这些模块中可以导出组件、函数或常量。
模块依赖树中的每个节点都是一个模块,每个分支代表该模块中的 import 语句。
如图一颗依赖树:
在这里插入图片描述
树的根节点是根模块,也称为入口文件main.js

依赖树和渲染树相比的不同点
1.成树的节点代表模块,而不是组件。
2.非组件模块,如 inspirations.js,在这个树中也有所体现。渲染树仅封装组件。
3.Copyright.js 出现在 App.js 下,但在渲染树中,Copyright 作为 InspirationGenerator 的子组件出现。

9.3 小结

  • 树是表示实体之间关系的常见方式,它们经常用于建模 UI。
  • 渲染树表示渲染中 React 组件之间的嵌套关系
  • 使用条件渲染,渲染树可能会在不同的渲染过程中发生变化。
  • 使用不同的属性值,组件可能会渲染不同的子组件。
  • 染树有助于识别顶级组件和叶子组件。
  • 依赖树表示 React 应用程序中的模块依赖关系。
  • 构建工具使用依赖树来捆绑必要的代码以部署应用程序。
  • 依赖树有助于调试大型捆绑包带来的渲染速度过慢的问题,以及发现哪些捆绑代码可以被优化。

总结

下一章:页面交互
一起加油吧^皿^
欢迎指正
在这里插入图片描述

  • 44
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值