Appearance
React 组件必须以大写字母开头
显示数据
js
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={{}} 并不是一个特殊的语法,而是 style={} JSX 大括号内的一个普通 {} 对象
##条件渲染
js
<div>
{isLoggedIn ? (
<AdminPanel />
) : (
<LoginForm />
)}
</div>##渲染列表
js
const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];
const listItems = products.map(product =>
<li key={product.id}>
{product.title}
</li>
);
return (
<ul>{listItems}</ul>
);为每个列表项显示多个 DOM 节点
如果你想让每个列表项都输出多个 DOM 节点而非一个的话,该怎么做呢?
Fragment 语法的简写形式 <> </> 无法接受 key 值,所以你只能要么把生成的节点用一个 <div> 标签包裹起来,要么使用长一点但更明确的 <Fragment> 写法:
Fragment相当于vue语法的Template
jsx
import { Fragment } from 'react';
// ...
const listItems = people.map(person =>
<Fragment key={person.id}>
<h1>{person.name}</h1>
<p>{person.bio}</p>
</Fragment>
);响应事件
js
function MyButton() {
function handleClick() {
alert('You clicked me!');
}
return (
<button onClick={handleClick}>
点我
</button>
);
}或者,你也可以在 JSX 中定义一个内联的事件处理函数:
jsx
<button onClick={function handleClick() {
alert('你点击了我!');
}}>或者,直接使用更为简洁箭头函数:
jsx
<button onClick={() => {
alert('你点击了我!');
}}>注意,onClick={handleClick} 的结尾没有小括号!不要 调用 事件处理函数:你只需 把函数传递给事件 即可。当用户点击按钮时 React 会调用你传递的事件处理函数
State用法
js
import { useState } from 'react';
export default function MyApp() {
return (
<div>
<h1>独立更新的计数器</h1>
<MyButton />
<MyButton />
</div>
);
}
function MyButton() {
//index 是一个 state 变量,setIndex 是对应的 setter 函数
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
点了 {count} 次
</button>
);
}你将从 useState 中获得两样东西:当前的 state(count),以及用于更新它的函数(setCount)。你可以给它们起任何名字,但按照惯例会像 [something, setSomething] 这样为它们命名。
第一次显示按钮时,count 的值为 0,因为你把 0 传给了 useState()。当你想改变 state 时,调用 setCount() 并将新的值传递给它。点击该按钮计数器将递增:
在组件中使用 reducer
最后,你需要将 tasksReducer 导入到组件中。记得先从 React 中导入 useReducer Hook:
js
import { useReducer } from 'react';接下来,你就可以替换掉之前的 useState:
js
const [tasks, setTasks] = useState(initialTasks);只需要像下面这样使用 useReducer:
js
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);useReducer 钩子接受 2 个参数:
1.一个 reducer 函数 2.一个初始的 state
prop用法
js
import { useState } from 'react';
export default function MyApp() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>共同更新的计数器</h1>
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}>
点了 {count} 次
</button>
);
}在声明 props 时, 不要忘记 ( 和 ) 之间的一对花括号 { 和 } :
jsx
function Avatar({ person, size }) {
// ...
}这种语法被称为 “解构”,等价于于从函数参数中读取属性:
jsx
function Avatar(props) {
let person = props.person;
let size = props.size;
// ...
}当你构建自己的组件时,你可以按你个人喜好命名事件处理函数的 prop。
jsx
function Button({ onSmash, children }) {
return (
<button onClick={onSmash}>
{children}
</button>
);
}
export default function App() {
return (
<div>
<Button onSmash={() => alert('正在播放!')}>
播放电影
</Button>
<Button onSmash={() => alert('正在上传!')}>
上传图片
</Button>
</div>
);
}阻止事件冒泡
如果你想阻止一个事件到达父组件,你需要像下面 Button 组件那样调用 e.stopPropagation() :
jsx
function Button({ onClick, children }) {
return (
<button onClick={e => {
e.stopPropagation();
onClick();
}}>
{children}
</button>
);
}
export default function Toolbar() {
return (
<div className="Toolbar" onClick={() => {
alert('你点击了 toolbar !');
}}>
<Button onClick={() => alert('正在播放!')}>
播放电影
</Button>
<Button onClick={() => alert('正在上传!')}>
上传图片
</Button>
</div>
);
}阻止默认行为
相当于vue:v-on:click.prevent
jsx
export default function Signup() {
return (
<form onSubmit={e => {
e.preventDefault();
alert('提交表单!');
}}>
<input />
<button>发送</button>
</form>
);
}使用 JSX 展开语法传递 props
有时候,传递 props 会变得非常重复:
jsx
function Profile({ person, size, isSepia, thickBorder }) {
return (
<div className="card">
<Avatar
person={person}
size={size}
isSepia={isSepia}
thickBorder={thickBorder}
/>
</div>
);
}重复代码没有错(它可以更清晰)。但有时你可能会重视简洁。一些组件将它们所有的 props 转发给子组件,正如 Profile 转给 Avatar 那样。因为这些组件不直接使用他们本身的任何 props,所以使用更简洁的“展开”语法是有意义的:
jsx
function Profile(props) {
return (
<div className="card">
<Avatar {...props} />
</div>
);
}这会将 Profile 的所有 props 转发到 Avatar,而不列出每个名字。
当你将内容嵌套在 JSX 标签中时,父组件将在名为 children 的 prop 中接收到该内容。例如,下面的 Card 组件将接收一个被设为 <Avatar /> 的 children prop 并将其包裹在 div 中渲染:
jsx
import Avatar from './Avatar.js';
function Card({children }) {
return (
<div className="card">
{children}
</div>
);
}
export default function Profile() {
return (
<Card>
<Avatar
size={100}
person={{
name: 'Katsuko Saruhashi',
imageId: 'YfeOqp2'
}}
/>
</Card>
);
}定义组件
返回语句可以全写在一行上,如下面组件中所示:
js
return <img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />;但是,如果你的标签和 return 关键字不在同一行,则必须把它包裹在一对括号中,如下所示:(内部没有分号)
js
return (
<div>
<img src="https://i.imgur.com/MK3eW3As.jpg" alt="Katherine Johnson" />
</div>
);ref
js
import { useRef } from 'react';
export default function Form() {
const inputRef = useRef(null);
function handleClick() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} />
<button onClick={handleClick}>
聚焦输入框
</button>
</>
);
}组件的导入和导出
js
//App.js
import Gallery from './Gallery.js';
export default function App() {
return (
<Gallery />
);
}js
//Gallery.js
function Profile() {
return (
<img
src="https://i.imgur.com/QIrZWGIs.jpg"
alt="Alan L. Hart"
/>
);
}
export default function Gallery() {
return (
<section>
<h1>了不起的科学家们</h1>
<Profile />
<Profile />
<Profile />
</section>
);
}默认导出 vs 具名导出
| 语法 | 导出语句 | 导入语句 |
|---|---|---|
| 默认 | export default function Button() {} | import Button from './Button.js'; |
| 具名 | export function Button() {} | import { Button } from './Button.js'; |
同一文件中,有且仅有一个默认导出,但可以有多个具名导出!
JSX 规则
1. 只能返回一个根元素
如果你不想在标签中增加一个额外的 <div>,可以用 <> 和 </> 元素来代替:
2. 标签必须闭合
3.使用驼峰式命名法给大部分属性命名!
由于 class 是一个保留字,所以在 React 中需要用 className 来代替
使用大括号:一扇进入 JavaScript 世界的窗户
jsx
export default function TodoList() {
const name = 'Gregorio Y. Zara';
return (
<h1>{name}的待办事项列表</h1>
);
}内联 style 属性 使用驼峰命名法编写。例如,HTML <ul style="background-color: black"> 在你的组件里应该写成 <ul style={{ backgroundColor: 'black' }}>。
在这个示例中,person JavaScript 对象包含 name 中存储的字符串和 theme 对象:
jsx
const person = {
name: 'Gregorio Y. Zara',
theme: {
backgroundColor: 'black',
color: 'pink'
}
};该组件可以这样使用来自 person 的值:
jsx
<div style={person.theme}>
<h1>{person.name}'s Todos</h1>条件渲染
与运算符(&&)
你会遇到的另一个常见的快捷表达式是 JavaScript 逻辑与(&&)运算符。在 React 组件里,通常用在当条件成立时,你想渲染一些 JSX,或者不做任何渲染。使用 &&,你也可以实现仅当 isPacked 为 true 时,渲染勾选符号。
jsx
return (
<li className="item">
{name} {isPacked && '✅'}
</li>
);当 JavaScript && 表达式 的左侧(我们的条件)为 true 时,它则返回其右侧的值(在我们的例子里是勾选符号)。但条件的结果是 false,则整个表达式会变成 false。在 JSX 里,React 会将 false 视为一个“空值”,就像 null 或者 undefined,这样 React 就不会在这里进行任何渲染。