react文档学习之
一、描述ui:
1、组件
可以使用html中的标签的本身样式在页面中使用,使其产生错落的格式:
在react中:
-函数和导入组件都需要首字母大写,否则将会在控制台报出警告并且无法渲染
-导出使用export default
2、使用 JSX 书写标签语言
介绍:JSX 是 JavaScript 语法扩展,可以在 JavaScript 文件中书写类似 HTML 的标签
将 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 )
2、标签需要闭合
3、使用驼峰法命名给大部分属性命名
变量名称不能包含 -
符号或者像 class
这样的保留字(class要改为className)
修改完以后的代码如下:
3、在 JSX 中通过大括号使用 JavaScript
注:如果要使用内联样式,大括号中需包裹一个对象
4、将 Props 传递给组件
1、将变量或者文本传递给组件
2、将JSX作为子组件传递
function Avatar ({src,alt}) {
return (
<img
src={src}
alt={alt}
/>
)
}
function Card ({ children }) {
return (
<div className="card">
{children}
</div>
)
}
export default function ProApp() {
const src = 'https://i.imgur.com/7vQD0fPs.jpg'
return (
<Card>
<Avatar
src={src}
alt='这是一个图片'
/>
</Card>
)
}
5、条件渲染
通过使用 JavaScript 的 if
语句、&&
和 ? :
运算符来选择性地渲染 JSX
实现同样效果还可以:
function ListItem ({ name, isPacked }) {
return <li>{ isPacked ? name + '✅' : name}</li>
}
或者:
function ListItem ({ name, isPacked }) {
return <li>{ name } { isPacked && '✅' }</li>
}
6、渲染列表
通过 JavaScript 的数组方法 来操作数组中的数据,从而将一个数据集渲染成多个相似的组件
const people = [
{
id: 0,
name: '凯瑟琳·约翰逊',
profession: '数学家',
accomplishment: '太空飞行相关数值的核算'
},
{
id: 1,
name: '马里奥·莫利纳',
profession: '化学家',
accomplishment: '北极臭氧空洞的发现'
},
{
id: 2,
name: '穆罕默德·阿卜杜勒·萨拉姆',
profession: '物理学家',
accomplishment: '关于基本粒子间弱相互作用和电磁相互作用的统一理论'
},
{
id: 3,
name: '珀西·莱温·朱利亚',
profession: '化学家',
accomplishment: '开创性的可的松药物、类固醇和避孕药的研究'
}
]
export default function ProApp() {
const chemists = people.filter(person =>
person.profession === '化学家'
)
const listItem = chemists.map(person =>
<li key={person.id}>
<b>{person.name}:</b>
{' ' + person.profession + ' '}
{`因${person.accomplishment}而闻名于世界`}
</li>
)
return (
<ul>
{listItem}
</ul>
)
}
运行结果:
7、保持组件纯粹
- 一个组件必须是纯粹的,就意味着:
- 只负责自己的任务。 它不会更改在该函数调用前就已存在的对象或变量。
- 输入相同,则输出相同。 给定相同的输入,组件应该总是返回相同的 JSX。
- 渲染随时可能发生,因此组件不应依赖于彼此的渲染顺序。
- 你不应该改变任何用于组件渲染的输入。这包括 props、state 和 context。通过 “设置” state 来更新界面,而不要改变预先存在的对象。
- 努力在你返回的 JSX 中表达你的组件逻辑。当你需要“改变事物”时,你通常希望在事件处理程序中进行。作为最后的手段,你可以使用
useEffect。
二、添加交互
1、响应事件
React 允许你向 JSX 中添加事件处理程序。事件处理程序是你自己的函数,它将在用户交互时被触发,如点击、悬停、焦点在表单输入框上等等
也可以将事件处理函数作为 props 传递
按照惯例,事件处理函数 props 应该以 on
开头,后跟一个大写字母。
function Button({onSmash, children}) {
return (
<button onClick={onSmash}>
{children}
</button>
)
}
export default function App () {
return (
<Button onSmash={() => alert('播放视频!')}>
播放视频
</Button>
)
}
注意:
- e.stopPropagation() 阻止触发绑定在外层标签上的事件处理函数。
- e.preventDefault() 阻止少数事件的默认浏览器行为。
2、State:组件的记忆
组件通常需要根据交互更改屏幕上显示的内容。输入表单应该更新输入字段,单击轮播图上的“下一个”应该更改显示的图片,单击“购买”应该将商品放入购物车。组件需要“记住”某些东西:当前输入值、当前图片、购物车。在 React 中,这种组件特有的记忆被称为 state。
useState Hook 提供了这两个功能:
- State 变量 用于保存渲染间的数据。
- State setter 函数 更新变量并触发 React 再次渲染组件。
useState
的唯一参数是 state 变量的初始值。在这个例子中,index
的初始值被useState(0)
设置为 0
。
每次你的组件渲染时,useState
都会给你一个包含两个值的数组:
- state 变量 (
index
) 会保存上次渲染的值。 - state setter 函数 (
setIndex
) 可以更新 state 变量并触发 React 重新渲染组件。
注意:
State 是隔离且私有的:如果你渲染同一个组件两次,每个副本都会有完全隔离的 state!改变其中一个不会影响另一个。
3、把一系列 state 更新加入队列
设置组件 state 会把一次重新渲染加入队列。但有时你可能会希望在下次渲染加入队列之前对 state 的值执行多次操作。
- React 会对 state 更新进行批处理
在下面的示例中,你可能会认为点击 “+3” 按钮会使计数器递增三次,因为它调用了 setNumber(number + 1)
三次:
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(number + 1);
setNumber(number + 1);
setNumber(number + 1);
}}>+3</button>
</>
)
}
但结果却是1,这是因为React 会等到事件处理函数中的 所有 代码都运行完毕再处理你的 state 更新。 这就是重新渲染只会发生在所有这些 setNumber()
调用 之后 的原因。
- 在下次渲染前多次更新同一个 state
这是一个不常见的用例,但是如果你想在下次渲染之前多次更新同一个 state,你可以像 setNumber(n => n + 1)
这样传入一个根据队列中的前一个 state 计算下一个 state 的 函数,而不是像 setNumber(number + 1)
这样传入 下一个 state 值。这是一种告诉 React “用 state 值做某事”而不是仅仅替换它的方法。
import { useState } from 'react';
export default function Counter() {
const [number, setNumber] = useState(0);
return (
<>
<h1>{number}</h1>
<button onClick={() => {
setNumber(n => n + 1);
setNumber(n => n + 1);
setNumber(n => n + 1);
}}>+3</button>
</>
)
}
在这里,n => n + 1
被称为 更新函数。当你将它传递给一个 state 设置函数时:
- React 会将此函数加入队列,以便在事件处理函数中的所有其他代码运行后进行处理。
- 在下一次渲染期间,React 会遍历队列并给你更新之后的最终 state。
4、更新 state 中的对象
state 中可以保存任意类型的 JavaScript 值,包括对象。但是,你不应该直接修改存放在 React state 中的对象。相反,当你想要更新一个对象时,你需要创建一个新的对象(或者将其拷贝一份),然后将 state 更新为此对象。
- 将 state 视为只读的
换句话说,应该 把所有存放在 state 中的 JavaScript 对象都视为只读的。
import { useState } from 'react';
export default function Counter() {
const [person, setPerson] = useState({
name: 'jack',
age: 22
});
return (
<>
<h1>小明的男朋友是{person.name},他今年{person.age}</h1>
<button onClick={() => {
setPerson({
name: '张三',
age: 18
})
}}>换人</button>
</>
)
}
当对象结构比较复杂的时候,修改的代码也会变得冗长如:
import { useState } from 'react';
export default function Counter() {
const [person, setPerson] = useState({
name: 'jack',
age: 22,
school: {
name: '北京大学',
address: '北京'
}
});
function handleSchoolChange (e) {
setPerson({
...person,
school: {
...person.school,
name: e.target.value
}
})
}
return (
<>
<h1>小明的男朋友是{person.name},他今年{person.age},他的学校是{person.school.name}</h1>
<button onClick={() => {
setPerson({
...person,
name: '张三',
age: 18
})
}}>换人</button>
<div>
学校名称:
<input
value={person.school.name}
onChange={handleSchoolChange}
/>
</div>
</>
)
}
- 使用 Immer 编写简洁的更新逻辑
如果 state 有多层的嵌套,应该考虑 将其扁平化。但是,如果你不想改变 state 的数据结构,你可能更喜欢用一种更便捷的方式来实现嵌套展开的效果。Immer 是一个非常流行的库,它可以让你使用简便但可以直接修改的语法编写代码,并会帮你处理好复制的过程。通过使用 Immer,你写出的代码看起来就像是你“打破了规则”而直接修改了对象。
尝试使用 Immer:
- 运行
npm install use-immer
添加 Immer 依赖- 用
import { useImmer } from 'use-immer'
替换掉import { useState } from 'react'
将上面例子修改为Immer:
import { useImmer } from 'use-immer'
export default function Counter() {
const [person, setPerson] = useImmer({
name: 'jack',
age: 22,
school: {
name: '北京大学',
address: '北京'
}
});
function handleSchoolChange (e) {
setPerson(draft => {
draft.school.name = e.target.value
})
}
return (
<>
<h1>小明的男朋友是{person.name},他今年{person.age},他的学校是{person.school.name}</h1>
<button onClick={() => {
setPerson(draft => {
draft.name = '张三'
draft.age = 18
})
}}>换人</button>
<div>
学校名称:
<input
value={person.school.name}
onChange={handleSchoolChange}
/>
</div>
</>
)
}
5、更新 state 中的数组
数组和对象一样,当你想要更新存储于 state 中的数组时,你需要用一个新数组设置 state。
下面是常见数组操作的参考表。当你操作 React state 中的数组时,你需要避免使用左列的方法,而首选右列的方法:
或者,你可以使用 Immer ,这样你便可以使用表格中的所有方法了。