1.react 语法
①数据渲染
函数组件将HTML结构直接写在函数的返回值中
JSX只能有一个根元素
JSX插值写法
插值可以使用的位置
1.标签内容;
2.标签属性
JSX 条件渲染:三目运算符;
JSX根据数据进行列表渲染:map()方法(注意需要唯一的key)
diff算法:key 用来在虚拟 DOM中 ,在同一级目录中,去保证当前元素的唯一性
②事件处理操作
在JSX里面属性通常是以驼峰形式命名
③状态处理
(1)对象属性修改
响应式数据驱动页面内容进行更新 ——>useState函数就能解决这个问题
useState(默认内容)函数调用会返回一个数组,可以解构出来为:第一个为当前数据的引用,第二个用来修改这个状态。
注意:set是一个直接换掉的操作,而非局部的修改。因此数据的更新需要将数据写全(简化书写可以通过展开运算符——注意新属性必须后写)。
(2)数组形态操作
添加和排序,指定位置删除,插入做更新同理也需要注意位置(可以借助filter函数)
2.组件通信与插槽
React 中的组件分为两种类型一种是 React DOM 组件,一种是 React 组件。
DOM 组件指的是 React支持的所有的 HTML和 SVG 标签
DOM 组件的类属性 className,同时也可以通过style写键值对(但要写成驼峰命名)来进行 style 属性的设置。
DOM组件示例:
展开语法:将所有属性提前预制为一个对象
JSX 的展开操作并不是ES6的展开运算符,不能在没有容器的地方单独使用。
在子组件拿到数据时,一般通过数据的解构。
不只是可以通过传递键值, 也可以传递状态表示 active 一般默认为 true。
子组件向父组件传递状态为:
子组件也是在props处声明事件
多级组件穿透的钩子 useContext() ——> 能够在组件树中传递数据,而无需显式地在每一层组件中通过 props 传递数据。
3.ReactHooks
(1)useRender
userRender(操作的函数, 状态默认值)
(2)useRef
useRef 不是一个响应式的状态,不会随着组件更新而更新。通过调用 useRef 返回包含的current属性的对象进行赋值。
默认子组件不对外开发内部功能
如果希望子组件内部的函数方法能够被父组件进行使用,便需要进行函数表示式进行定义。
子组件ref为childRef便能够实现在父组件使用子组件的函数方法。
(3)useEffect
即副作用函数,组件渲染时执行 。
后面依赖数组为 变量状态变更就会导致副作用重新执行。
(4)useMemo
进行数据缓存的钩子。用于在组件渲染过程中缓存计算结果。它接收一个创建函数和一个依赖数组,仅当依赖数组中的某个值改变时,才会重新计算创建函数的结果。这有助于避免在每次渲染时都进行昂贵的计算,从而提升性能。
import React, { useMemo, useState } from 'react';
function FilterList({ items }) {
const [searchTerm, setSearchTerm] = useState('');
// 使用 useMemo 来缓存过滤后的结果
const filteredItems = useMemo(() => {
return items.filter(item => item.toLowerCase().includes(searchTerm.toLowerCase()));
}, [items, searchTerm]);
return (
<div>
<input
type="text"
value={searchTerm}
onChange={e => setSearchTerm(e.target.value)}
placeholder="Search..."
/>
<ul>
{filteredItems.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
</div>
);
}
根据一个列表和一个搜索词来过滤结果。可以使用
useMemo
来缓存过滤后的结果,避免每次输入改变时都重新计算整个列表。
(5)useCallback
进行函数缓存的钩子(解决父组件变更导致子组件重新渲染的问题)。用于缓存函数定义。它接收一个返回函数的函数和一个依赖数组,仅当依赖数组中的某个值改变时,才会返回一个新的函数。这主要用于优化性能,特别是在父组件传递给子组件的函数作为 props 时,可以避免子组件因父组件重新渲染而接收到新的函数引用,从而避免不必要的重新渲染。
import React, { useState, useCallback } from 'react';
function ParentComponent() {
const [count, setCount] = useState(0);
// 使用 useCallback 来缓存 handleClick 函数
const handleClick = useCallback(() => {
console.log('Button clicked', count);
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<ChildComponent onButtonClick={handleClick} />
</div>
);
}
function ChildComponent({ onButtonClick }) {
console.log('ChildComponent rendered');
return (
<button onClick={onButtonClick}>Click me from Child</button>
);
}
父组件有一个按钮,点击按钮时会更新状态,并将一个函数传递给子组件,因此可以使用
useCallback
来确保传递给子组件的函数引用不会因父组件的重新渲染而改变。
(6)useState
setState 是异步的,也就是说,状态的更新不会立即生效。在状态更新之后立即读取状态值可能会得到旧的值。因此,在需要立即使用最新状态的地方,可以考虑使用 setState 的回调函数
项目经验:
1.样式初始化顺序
2.配置路径别名
目前ts对@指向src目录的提示是不支持的,vite默认也是不支持的。
所以需要手动配置@符号的指向,在vite.config.ts中添加配置:
路径别名提示:
虽然现在路径别名已经有了,但是在文件中输入@是没有提示路径的。
需要在tsconfig.json中:添加两项配置 :
3.模块化引入样式
import "./组件.scss" 全局引入的样式会造成污染,需要进模块化引入(类似Vue的scoped):
4.路由配置
(1)组件化配置路由:
(2)编程式(对象写法)导航
路由如果需要有操作,就不能写没有return的简写方法。
5.数据储存
-
Cookie:
- 用途:主要用于存储用户的登录状态(如会话标识)、个人设置等小量数据。
- 特点:
- 存储大小限制:通常每个Cookie的大小限制为4KB。
- 每次HTTP请求都会携带Cookie,因此对于大量数据不适合使用Cookie。
- 有有效期限制,可以设置过期时间,过期后浏览器会自动删除。
- 存储在客户端,但通过HTTP请求发送到服务器,因此不安全,容易受到XSS和CSRF攻击。
-
Session:
- 用途:用于服务器端存储用户状态,通常用于跟踪用户的登录状态。
- 特点:
- 存储在服务器端,客户端保存一个Session ID来标识Session。
- 存储空间理论上无限制,取决于服务器的内存和存储能力。
- 可以存储任何类型的数据,但通常用于存储用户状态和会话信息。
- 需要服务器支持,并且需要维护Session ID和Session数据的映射关系。
-
IndexedDB:
- 用途:用于存储大量结构化数据,适合复杂数据和大量数据的存储。
- 特点:
- 存储大小限制较高,通常可以达到几GB到几十GB。
- 支持事务处理,可以保证数据的一致性。
- 支持丰富的查询API,可以对存储的数据进行索引和查询。
- 存储在客户端,数据存储在浏览器中,不随HTTP请求发送。
-
localStorage:
- 用途:用于存储少量的非敏感数据,如用户偏好设置、主题设置等。
- 特点:
- 存储大小限制:通常为5MB左右。
- 数据持久存储,除非主动清除,否则数据会一直保存在浏览器中。
- 仅在客户端可用,不随HTTP请求发送到服务器。
- 同源策略限制,只有同源页面才能访问相同的localStorage数据。