跳到主要内容

Day 1 - 快速入门

隐藏的中文文档

React 已经上线了新文档站点,打开英文站点 https://react.dev 一看,发现并没有中文切换选项

但实际上在 Google 搜下是有的:https://zh-hans.react.dev

如何创建和嵌套组件

React 程序是由组件组成的。一个组件是 UI 的一部分,拥有自己的逻辑和外观。组件可以小到一个按钮,也可以大到一个页面。

React 组件是返回标签的 JavaScript 函数:

function MyButton() {
return <button>Click me</button>;
}

这样就声明了一个 MyButton 组件,可以嵌套到另一个组件中:

export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton />
</div>
)
}

MyButton 是以大写字母开头的,可以以此来识别 React 组件 —— React 组件必须以大写字母开头,而 HTML 标签则必须是小写字母

export default 关键字指定了文件中的主要组件,相关语法可以参考:Export and Import

那么,有没有 playground 可以看下运行效果不?

DEMO 1:https://stackblitz.com/edit/stackblitz-starters-pebieb

上面所使用的标签语法被称为 JSX(HTML in JS),JSX 是可选的,但大多数 React 项目都会使用 JSX

JSX 比 HTML 更加严格:

  • 必须闭合标签
  • 不能返回多个 JSX 标签 —— 必须包裹在一个共享的父级中,比如 <div>...</div><>...</>
function AboutPage() {
return (
<>
<h1>About</h1>
<p>Hello there.<br />How do you do?</p>
</>
);
}

如果你有大量的 HTML 需要移植到 JSX 中,你可以使用 在线转换器(HTML -> JSX)

如何添加标签和样式

使用 className 来指定一个 CSS 的 class(与 HTML 的 class 属性类似):

<img className="avatar" />

然后可以在一个单独的 CSS 文件中为它编写 CSS 规则:

/* In your CSS */
.avatar {
border-radius: 50%;
}

React 并没有规定你如何添加 CSS 文件,最简单的方式是使用 HTML 的 <link> 标签

如何显示数据

在代码中嵌入变量并展示给用户:

return (
<h1>
{ user.name }
</h1>
);

还可以将 JSX 属性 “转义到 JavaScript”,但你必须使用大括号而非引号:

return (
<img
className="avatar"
src={user.imageUrl}
/>
);

也可以把更为复杂的表达式放入 JSX 的大括号内,示例:

const user = {
name: 'Hedy Lamarr',
imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
imageSize: 90,
};

export default function Profile() {
return (
<>
<h1>{user.name}</h1>
<img
className="avatar"
src={user.imageUrl}
alt={'Photo of ' + user.name}
style={{
width: user.imageSize,
height: user.imageSize
}}
/>
</>
);
}

DEMO 2: https://stackblitz.com/edit/stackblitz-starters-pebieb

如何渲染条件和列表

React 没有特殊的语法来编写条件语句,因此你使用的就是普通的 JavaScript 代码。

使用 if 语句根据条件引入 JSX:

let content
if (isLoggedIn) {
content = <AdminPanel />
} else {
content = <loginForm />
}
return (
<div>
{content}
</div>
)

条件 ? 运算符的写法:

<div>
{isLoggedIn ? (<AdminPanel />) : (<LoginForm />)}
</div>

当你不需要 else 分支时,你还可以使用 逻辑 && 语法:

<div>
{isLoggedIn && <AdminPanel />}
</div>

渲染列表:可以使用 for 循环和数组的 map() 函数 来渲染组件列表:

示例:

const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];

在你的组件中,使用 map() 函数将这个数组转换为 <li> 标签构成的列表:

const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);

return (
<ul>{listItems}</ul>
);

注意:每个 <li> 有一个 key 属性,用于在其兄弟节点中唯一标识该元素。如果你在后续插入、删除或重新排序这些项目,React 将依靠你提供的 key 来思考发生了什么。

DEMO 3:https://stackblitz.com/edit/stackblitz-starters-pebieb

如何对事件做出响应并更新界面

可以通过在 组件中 声明事件处理函数来响应事件:

function MyButton() {
function handleClick() {
alert('You clicked me!');
}

return (
<button onClick={handleClick}>
Click me
</button>
);
}

注意:onClick = { handleClick } 的结尾没有小括号!不要调用事件处理函数,你只需把函数传递给事件即可。当用户点击按钮时 React 会调用你传递的事件处理函数。

通常你会希望你的组件 “记住” 一些信息并展示出来,比如一个按钮被点击的次数。要做到这一点,你需要在你的组件中添加 state

首先,从 React 引入 useState

import { useState } from 'react';

然后,在你的组件中声明一个 state 变量:

function MyButton() {
const [count, setCount] = useState(0);
// ...
}

你将从 useState 中获得两样东西:当前的 state(count),以及用于更新它的函数(setCount)。你可以给它们起任何名字,但按照惯例会像 [something, setSomething] 这样为它们命名

如果你多次渲染同一个组件,每个组件都会拥有自己的 state

import { useState } from 'react';

export default function MyApp() {
return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<MyButton />
</div>
);
}

function MyButton() {
const [count, setCount] = useState(0);

function handleClick() {
setCount(count + 1);
}

return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}

DEMO 4:https://stackblitz.com/edit/stackblitz-starters-rjkzu3

使用 HOOK

use 开头的函数被称为 HookuseState 是 React 提供的一个内置 Hook。

你可以在 React API 参考 中找到其他内置的 Hook,也可以通过组合现有的 Hook 来编写属于你自己的 Hook。

Hook 比普通函数更为严格。你只能在你的组件(或其他 Hook)的顶层调用 Hook。如果你想在一个条件或循环中使用 useState,请提取一个新的组件并在组件内部使用它。

如何在组件间共享数据

问题:组件共享数据并一起更新

为了使得 MyButton 组件显示相同的 count 并一起更新,你需要将各个按钮的 state “向上” 移动到最接近包含所有按钮的组件之中。

how-component-share-data

具体操作:

  1. MyButtonstate 上移到 MyApp
  2. MyApp 中的点击事件处理函数以及 state 一同向下传递到 每个 MyButton
  3. 改变 MyButton 以读取从父组件传递来的 prop

示例:

import React from 'react';
import './style.css';
import { useState } from 'react';

export const MyButton = ({ count, onClick }) => {
return <button onClick={onClick}>Click Me {count} time.</button>;
};

export default function App() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
};
return (
<div>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}

DEMO 5:https://stackblitz.com/edit/stackblitz-starters-vxpy3a

当你点击按钮时,onClick 处理程序会启动,每个按钮的 onClick prop 会被设置为 MyApp 内的 handleClick 函数,所以函数内的代码会被执行。

该代码会调用 setCount(count + 1),使得 state 变量 count 递增。

新的 count 值会被作为 prop 传递给每个按钮,因此它们每次展示的都是最新的值。

这种方式称为“状态提升(lifting state up)” —— 通过向上移动 state,我们实现了在组件间共享数据。

总结

学习了:

  • 如何创建和嵌套组件
  • 如何添加标签和样式
  • 如何显示数据
  • 如何渲染条件和列表
  • 如何对事件做出响应并更新界面
  • 如何在组件间共享数据

参考