快速入门
欢迎访问 React 文档!本页将向您介绍 80% 的 React 概念,这些概念将是您日常开发中经常用到的。
You will learn
- 如何创建并嵌套组件
- How to add markup and styles
- 如何展示数据
- How to render conditions and lists
- 如何响应事件并更新屏幕显示
- 如何在组件间共享数据
创建并嵌套组件
React 应用程序是由组件(component)组成的。组件是 UI(用户界面)的组成部分,拥有自己的逻辑和外观。一个组件可以小到一个按钮,大到整个页面。
React 组件就是 JavaScript 函数(function),此类函数返回由标签语言编写的用户界面:
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 标签必须全部为小写字母。
看看成果:
function MyButton() { return ( <button> Click me </button> ); } export default function MyApp() { return ( <div> <h1>Welcome to my app</h1> <MyButton /> </div> ); }
export default
关键字在文件中标明了主要组件。如果你对此 JavaScript 语法还不熟悉,请参考 MDN 和 javascript.info 上的参考手册。
编写 JSX 语法的标签
你在前面看到的标记语言(markup syntax)称为 JSX。JSX 不是必须要用的,但是因为使用方便,所以大多数 React 项目都使用 JSX。所有 我们推荐的用于本地开发的工具 都自带对 JSX 的支持。
JSX 的语法比 HTML 更严格。类似 <br />
这样的标签是必须要关闭的。并且,组件也不能返回多个并列最高层级的 JSX 标签,你必须为所有最高层级的标签添加一个共同的父标签,例如使用 <div>...</div>
或 <>...</>
作为父标签:
function AboutPage() {
return (
<>
<h1>About</h1>
<p>Hello there.<br />How do you do?</p>
</>
);
}
如果你需要将大量 HTML 代码移植到 JSX 语法,可以使用这个 在线转换器。
添加样式
在 React 中,通过 className
这个属性来指定 CSS 类。它和 HTML 的 class
属性的功能是一样的:
<img className="avatar" />
然后在一个单独的 CSS 文件中为其编写 CSS 样式:
/* In your CSS */
.avatar {
border-radius: 50%;
}
React 没有规定如何添加 CSS 文件。最简单的方式是添加一个 <link>
标签到页面的 HTML 代码中。如果你使用了构建工具或框架,请查阅其相关文档,以便了解如何将 CSS 文件添加到你的项目中。
显示数据
JSX 允许你将标签语言混入到 JavaScript 代码中。通过花括号可以让你在标签语言中输出 JavaScript 变量,并将其展示给用户。例如,以下代码将显示 user.name
的值:
return (
<h1>
{user.name}
</h1>
);
你也可以在 JSX 的属性中嵌入 JavaScript 代码,但是必须使用花括号,不能使用引号。例如,className="avatar"
将 "avatar"
字符串作为 CSS 类进行传递,而 src={user.imageUrl}
首先读取 user.imageUrl
变量的值,然后将该值作为 src
的属性进行传递:
return (
<img
className="avatar"
src={user.imageUrl}
/>
);
你也可以在 JSX 中通过花括号添加更复杂的 JavaScript 表达式,例如 字符串拼接:
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 }} /> </> ); }
在上述示例中,style={{}}
不是一种特殊语法,而是 {}
所代表的对象(object)被放在了 style={ }
的花括号里面了。当 CSS 样式依赖 JavaScript 变量的值时,可以通过 style
属性进行设置。
Conditional rendering
在 React 中,没有用于书写条件表达式的特殊语法。相反,你只需使用常规的 JavaScript 条件表达式即可。例如,你可以使用 if
语句来根据条件包含不同的 JSX 代码:
let content;
if (isLoggedIn) {
content = <AdminPanel />;
} else {
content = <LoginForm />;
}
return (
<div>
{content}
</div>
);
如果你喜欢更紧凑的代码,可以使用 ?
条件运算符。与 if
不同,他能与 JSX 语法混合书写:
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>
当你不需要 else
分支时,还可以使用更简短的 &&
语法:
<div>
{isLoggedIn && <AdminPanel />}
</div>
所有这些方法All of these approaches also work for conditionally specifying attributes. If you’re unfamiliar with some of this JavaScript syntax, you can start by always using if...else
.
Rendering lists
You will rely on JavaScript features like for
loop and the array map()
function to render lists of components.
例如,假设你有一个产品列表:
const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];
Inside your component, use the map()
function to transform an array of products into an array of <li>
items:
const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);
Notice how <li>
has a key
attribute. For each item in a list, you should pass a string or a number that uniquely identifies that item among its siblings. Usually, a key should be coming from your data, such as a database ID. React will rely on your keys to understand what happened if you later insert, delete, or reorder the items.
const products = [ { title: 'Cabbage', isFruit: false, id: 1 }, { title: 'Garlic', isFruit: false, id: 2 }, { title: 'Apple', isFruit: true, id: 3 }, ]; export default function ShoppingList() { const listItems = products.map(product => <li key={product.id} style={{ color: product.isFruit ? 'magenta' : 'darkgreen' }} > {product.title} </li> ); return ( <ul>{listItems}</ul> ); }
Responding to events
You can respond to events by declaring event handler functions inside your components:
function MyButton() {
function handleClick() {
alert('You clicked me!');
}
return (
<button onClick={handleClick}>
Click me
</button>
);
}
Notice how onClick={handleClick}
has no parentheses at the end! Do not call the event handler function: you only need to pass it down. React will call your event handler when the user clicks the button.
Updating the screen
Often, you’ll want your component to “remember” some information and display it. For example, maybe you want to count the number of times a button is clicked. To do this, add state to your component.
First, import useState
from React:
import { useState } from 'react';
Now you can declare a state variable inside your component:
function MyButton() {
const [count, setCount] = useState(0);
You will get two things from useState
: the current state (count
), and the function that lets you update it (setCount
). You can give them any names, but the convention is to call them like [something, setSomething]
.
The first time the button is displayed, count
will be 0
because you passed 0
to useState()
. When you want to change state, call setCount()
and pass the new value to it. Clicking this button will increment the counter:
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}
React will call your component function again. This time, count
will be 1
. Then it will be 2
. And so on.
If you render the same component multiple times, each will get its own state. Try clicking each button separately:
import { useState } from 'react'; function MyButton() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <button onClick={handleClick}> Clicked {count} times </button> ); } export default function MyApp() { return ( <div> <h1>Counters that update separately</h1> <MyButton /> <MyButton /> <MyButton /> </div> ); }
Notice how each button “remembers” its own count
state and doesn’t affect other buttons.
Using Hooks
Functions starting with use
are called Hooks. useState
is a built-in Hook provided by React. You can find other built-in Hooks in the React API reference. You can also write your own Hooks by combining the existing ones.
Hooks are more restrictive than regular functions. You can only call Hooks at the top level of your components (or other Hooks). If you want to useState
in a condition or a loop, extract a new component and put it there.
Sharing data between components
In the previous example, each button had its own independent counter:
- MyApp
- MyButton (count: 3)
- MyButton (count: 1)
- MyButton (count: 2)
However, you’ll often need components to share data and always update together.
To make all buttons display the same count
and update together, you need to move the state from the individual buttons “upwards” to the closest component containing all of them. In this example, it is MyApp
:
- MyApp (count: 3)
- MyButton
- MyButton
- MyButton
Here’s how you can express this in code.
First, move the state up from MyButton
into MyApp
:
function MyButton() {
// ... we're moving code from here ...
}
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update separately</h1>
<MyButton />
<MyButton />
<MyButton />
</div>
);
}
Then, pass the state down from MyApp
to each MyButton
, together with the shared click handler. You can pass information to MyButton
using the JSX curly braces, just like you previously did with built-in tags like <img>
:
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update together</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
The information you pass down like this is called props. Now the MyApp
component contains the count
state and the handleClick
event handler, and passes both of them down as props to each of the buttons.
Finally, change MyButton
to read the props you have passed from its parent component:
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
Clicked {count} times
</button>
);
}
When you click the button, the onClick
handler fires. Each button’s onClick
prop was set to the handleClick
function inside MyApp
, so the code inside of it runs. That code calls setCount(count + 1)
, incrementing the count
state variable. The new count
value is passed as a prop to each button, so they all show the new value.
This is called “lifting state up”. By moving state up, we’ve shared it between components.
import { useState } from 'react'; function MyButton({ count, onClick }) { return ( <button onClick={onClick}> Clicked {count} times </button> ); } export default function MyApp() { const [count, setCount] = useState(0); function handleClick() { setCount(count + 1); } return ( <div> <h1>Counters that update together</h1> <MyButton count={count} onClick={handleClick} /> <MyButton count={count} onClick={handleClick} /> <MyButton count={count} onClick={handleClick} /> </div> ); }
Next Steps
By now, you know the basics of how to write React code!
Head to Thinking in React to see how it feels to build a UI with React in practice.