描述UI
每个 React 组件都是一个 JavaScript 函数,它可能包含一些标签,React 会将其渲染到浏览器中。React 组件使用一种叫做 JSX 的语法扩展来表示该标签。JSX 看起来很像 HTML,但它更为严格,可以显示动态信息。
如果我们直接把现有的 HTML 标签粘贴到 React 组件中,它并不一定能成功运行成功!
这里推荐一个在线转换器:transform.tools/ 它能够转换各种代码极其方便。
在 JSX 中使用大括号编写 JavaScript
JSX 可以让你在 JavaScript 文件中编写类似 HTML 的标签语法,使渲染逻辑和内容展示维护在同一个地方。
大括号内的任何 JavaScript 表达式都能正常运行
使用 “双大括号”:JSX 中的 CSS 和 对象
除了字符串、数字和其它 JavaScript 表达式,你甚至可以在 JSX 中传递对象。对象也用大括号表示,例如 { name: "Hedy Lamarr", inventions: 5 }。因此,为了能在 JSX 中传递,你必须用另一对额外的大括号包裹对象:person={{ name: "Hedy Lamarr", inventions: 5 }}。
你可能在 JSX 的内联 CSS 样式中就已经见过这种写法了。React 不要求你使用内联样式(使用 CSS 类就能满足大部分情况)。但是当你需要内联样式的时候,你可以给 style 属性传递一个对象
const person = {
name: 'Gregorio Y. Zara',
age: 33
};
export default function TodoList() {
return (
<div>
<h1 style={{
backgroundColor: 'black',
color: 'pink'
}}>name: {person.name}</h1>
<h1>age: {person.age}</h1>
</div>
);
}
JSX规则
1. 只能返回一个根元素
如果想要在一个组件中包含多个元素,需要用一个父标签把它们包裹起来(<>
/<div>
)。
为什么多个 JSX 标签需要被一个父元素包裹?
2. 标签必须闭合
JSX 要求标签必须正确闭合。像 <img>
这样的自闭合标签必书写成 <img />
,而像 <li>oranges
这样只有开始标签的元素必须带有闭合标需签,需要改为 <li>oranges</li>
。
3. 使用驼峰式命名法给 所有 大部分属性命名!
JSX 最终会被转化为 JavaScript,而 JSX 中的属性也会变成 JavaScript 对象中的键值对。在你自己的组件中,经常会遇到需要用变量的方式读取这些属性的时候。但 JavaScript 对变量的命名有限制。例如,变量名称不能包含 -
符号或者像 class
这样的保留字。
这就是为什么在 React 中,大部分 HTML 和 SVG 属性都用驼峰式命名法表示。例如,需要用 strokeWidth
代替 stroke-width
。由于 class
是一个保留字,所以在 React 中需要用 className
来代替。这也是 DOM 属性中的命名:
组件通信
React 组件使用 props 来进行组件之间的通讯。每个父组件都可以通过为子组件提供 props 的方式来传递信息。你可以通过它们传递任何 JS 的值,包括对象、数组、函数、甚至是 JSX!
不能改变 props。当你需要交互性时,你可以设置 state。
export default function Profile() {
return (
<>
<Avatar
size={100}
person={{
name: 'Katsuko Saruhashi',
imageId: 'YfeOqp2',
url: 'http://xxxxx'
}}
/>
</>
);
}
function Avatar({ person, size }) {
return (
<img
className="avatar"
src={person.url}
alt={person.name}
width={size}
height={size}
/>
);
}
将Props传递给组件
- 给prop指定一个默认值:如果你想在没有指定值的情况下给 prop 一个默认值,你可以通过在参数后面写
=
和默认值来进行解构:
function Avatar({ person, size = 100 }) {
// ...
}
使用 JSX 展开语法传递 props
有时候,传递 props 会变得非常重复
function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}
// 使用展开语法让jsx更加简洁
function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}
将 JSX 作为子组件传递
Card
组件将接收一个被设为 <Tiitle />
的 children
prop 并将其包裹在 div 中渲染
function Card({ children }) {
return (
<div className="card">
{children}
</div>
);
}
function Title() {
return (
<h2>Hello React</h2>
)
}
export default Show() {
return (
<Card
<Title />
/>
)
}
条件渲染
在 React 中,你可以使用 JavaScript 语法,如 if
语句、&&
和 ? :
操作符有条件地渲染 JSX。
在一些情况下,你不想有任何东西进行渲染。比如,你不想显示已经打包好的物品。但一个组件必须返回一些东西。这种情况下,你可以直接返回 null
。实际上,在组件里返回 null 并不常见, 更加常见的是使用三目运算符。
与运算符(&&
)
在 React 组件里,通常用在当条件成立时,你想渲染一些 JSX,或者不做任何渲染。使用 &&,你也可以实现仅当 isPacked 为 true 时,渲染勾选符号。
return (
<li className="item">
{name} {isPacked && '✔'}
</li>
);
- 在 JSX 中,
{cond ? <A /> : <B />}
表示 “当cond
为真值时, 渲染<A />
,否则<B />
” 。 - 在 JSX 中,
{cond && <A />}
表示 “当cond
为真值时, 渲染<A />
,否则不进行渲染” 。 - 快捷的表达式很常见,但如果你更倾向于使用
if
,你也可以不使用它们,。
渲染列表
通常,你需要根据数据集合来渲染多个较为类似的组件。你可以在 React 中使用 JavaScript 的 filter()
和 map()
来实现数组的过滤和转换,将数据数组转换为组件数组。
对于数组的每个元素项,你需要指定一个 key
。通常你需要使用数据库中的 ID 作为 key
。即使列表发生了变化,React 也可以通过 key 来跟踪每个元素在列表中的位置。
保持组件的纯粹
React 的渲染过程必须自始至终是纯粹的。组件应该只 返回 它们的 JSX,而不 改变 在渲染前,就已存在的任何对象或变量 — 这将会使它们变得不纯粹!
js纯函数的定义:
- 只负责自己的任务。 它不会更改在该函数调用前就已存在的对象或变量。
- 输入相同,输出也相同。 在输入相同的情况下,对纯函数来说应总是返回相同的结果。
严格遵循纯函数的定义编写组件,可以让代码库体量增长时,避免一些令人困惑的错误和不可预测的行为。
示例:
// 非纯函数组件
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 />
</>
);
}
// 你可以通过传递一个 `props` 来使这个组件变得纯粹,而非修改已经存在的变量
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} />
</>
);
}
注意事项
你可以只定义组件一次,然后按需多处和多次使用。
文件导入和导出
一个文件中只允许有一个默认导出,但可以有多个具名导出。当使用默认导入时,你可以在 import 语句后面进行任意命名。如此你能获得与默认导出一致的内容。相反,对于具名导入,导入和导出的名字必须一致。这也是为什么称其为 具名 导入的原因!
为了减少在默认导出和具名导出之间的混淆,一些团队会选择只使用一种风格(默认或者具名),或者禁止在单个文件内混合使用。这因人而异,选择最适合你的即可!