React笔记
基础
语法基础与规范
JSX
注意事项。JSX
必须有一个根节点,如果没有,可以用幽灵节点<></>
代替。- 所有标签必须闭合,成对闭合或者自闭和都可以。
JSX
采用小驼峰命名法,对于class
要转化成className
,for
需要转化成htmlFor
,以防止js
关键字冲突。JSX
支持换行,如果需要换行需要加上()
,防止bug
出现。- 注释在模板中的书写方式:
{/* 苏苏苏 */}
。
jsx
的列表渲染React
函数组件- 函数组件首字母必须大写。
- 函数组件必须有返回值,若不需要渲染内容则返回
null
。 - 使用函数组件可以自闭和也可以成对闭合。
注意在
React
中的样式绑定只能使用驼峰规则,这点和Vue
不一样,vue
可以使用kebab-cased
命名方式。React
的纯函数概念。- 一个组件必须是纯粹的,就意味着:
- 只负责自己的任务。 它不会更改在该函数调用前就已存在的对象或变量。
- 输入相同,则输出相同。 给定相同的输入,组件应该总是返回相同的
JSX
。
- 渲染随时可能发生,因此组件不应依赖于彼此的渲染顺序。
- 你不应该改变任何用于组件渲染的输入。这包括
props
、state
和context
。通过 “设置”state
来更新界面,而不要改变预先存在的对象。 - 努力在你返回的
JSX
中表达你的组件逻辑。当你需要“改变事物”时,你通常希望在事件处理程序中进行。作为最后的手段,你可以使用useEffect
。 - 编写纯函数需要一些练习,但它充分释放了
React
范式的能力。
- 一个组件必须是纯粹的,就意味着:
状态(state)
useState
特征- 每个渲染(以及其中的函数)始终“看到”的是
React
提供给这个 渲染的state
快照。 - 过去创建的事件处理函数拥有的是创建它们的那次渲染中的
state
值。 setState
推入队列后遍历当你在下次渲染期间调用
useState
时,React
会遍历队列。之前的number state
的值是0
,所以这就是React
作为参数n
传递给第一个更新函数的值。然后React
会获取你上一个更新函数的返回值,并将其作为n
传递给下一个更新函数,以此类推…注意永远不要直接修改
state
!!!
- 每个渲染(以及其中的函数)始终“看到”的是
Immer
简化react
对象的修改使用
Immer
编写数组更简单的逻辑State
不依赖于特定的函数调用或在代码中的位置,它的作用域“只限于”屏幕上的某块特定区域。你渲染了两个<Gallery />
组件,所以它们的state
是分别存储的。
还要注意Page
组件“不知道”关于Gallery state
的任何信息,甚至不知道它是否有任何state
。与props
不同,state
完全私有于声明它的组件。父组件无法更改它。这使你可以向任何组件添加或删除state
,而不会影响其他组件。不要在
state
中镜像props
由于state
只会在第一次渲染期间初始化,后续props
发生更新后,这样的代码不会发生更新。只有当你 想要 忽略特定
props
属性的所有更新时,将props
“镜像”到state
才有意义。按照惯例,prop
名称以initial
或default
开头,以阐明该prop
的新值将被忽略:React
中的Hook
只能在组件或者自己的Hook
的顶层调用,而不能嵌套调用。原因为Hooks
的执行需要严格按照其调用顺序,Hooks
的调用顺序是一致的,从而避免了状态的混乱或者副作用的错误。- 注意
React
中的setState
方法中的更改只会在下一次渲染时才会生效。 useState
内部原理的简单实现。index.js
index.html
相同位置的相同组件会使得 state 被保留下来:记住 对
React
来说重要的是组件在UI
树中的位置,而不是在JSX
中的位置!
重置state
有两种方法:- 在不同的位置渲染组件
- 添加唯一的
key
值
Props
在
React
中使用props
传递参数对于
React
中的函数组件,props
相当于一个整体对象,这里是将其解构赋值出来。React
中的默认参数与js
中函数的默认参数一致,但位置随意。在
React
中通过扩展运算符传递参数你可以使用
<Avatar {...props} />
JSX
展开语法转发所有props
,但不要过度使用它!React
中的列表渲染对于
React
和Vue
中的组件中的key
,key
会作为组件中的一个特殊的属性而不会作为props
传入。React
中props
的children
属性如果有多个同级的JSX
元素传递过来,则children
是数组的形式。
注意事项
React
使用Fragment
标签来充当幽灵标签,用来添加key
值,这时候不能使用<></>
。React
只能渲染字符串,数字,布尔值,null
,undefined
,数组或者React
元素在
React
中绑定一个事件的捕获模式,即在事件名称末尾添加Capture
。React
如果需要触发组件的re-render
,除了自身的setState
方法,如果父组件的变量作为props
传递给子组件,那么如果该变量发生变化也会引起子组件的re-render
。井字棋游戏示例代码
React Router
创建
React Router
的基本过程React
中子路由的创建,使用<Outlet />
渲染路由相当于vue
中的<RouterView />
。React Router
中通过向路由配置的loader
配置项传递一个
具有返回值的函数,然后通过useLoaderData
函数进行数据的获取。React Router
会截取页面中表单提交的行为,并将其转发到目前路由的action
当中。edit.tsx
main.tsx
使用
React Router
中的JSX Routes
。React Router
集中式路由配置react router
中jsx
方式的嵌套路由React
路由懒加载以及回调显示vite
配置路径别名的方案。- 安装
@types/node
库,便于后续文件的引用。 打开
vite.config.ts
进行路径别名的配置,使vite
能够识别@
。在
tsconfig.json
中进行配置,使得vscode
能使用@
进行智能提示。
- 安装
Mobx
mobx
模块化的基本用法。定义单独的
store
在
index.ts
中统一进行注入使用
store
组件通信
父传子
子传父
兄弟组件通信,核心思路为变量提升。
跨组件间通信
小案例
Hooks
useState
- 如果就是初始化一个普通的数据 直接使用
useState(普通数据)
即可 - 如果要初始化的数据无法直接得到需要通过计算才能获取到,使用
useState(()=>{})
useEffect
不添加依赖项
组件首次渲染执行一次,以及不管是哪个状态更改引起组件更新时都会重新执行
- 组件初始渲染
- 组件更新 (不管是哪个状态引起的更新)
添加空数组
组件只在首次渲染时执行一次
添加特定依赖项
副作用函数在首次渲染时执行,在依赖项发生变化时重新执行
useEffect
回调函数中用到的数据(比如,count
)就是依赖数据,就应该出现在依赖项数组中,如果不添加依赖项就会报错。如果想要清理副作用 可以在副作用函数中的末尾
return
一个新的函数,在新的函数中编写清理副作用的逻辑- 组件卸载时自动执行
组件更新时,下一个
useEffect
副作用函数执行之前自动执行
异步的正确写法
useRef
获取一个在重新渲染中保存,但改变其值不会触发页面重新渲染的对象。
获取
DOM
实例。通过
Ref
函数参数的形式管理Ref
列表:子组件通过
forwardRef
选择是否暴露DOM
元素
它是这样工作的:<MyInput ref={inputRef} />
告诉React
将对应的DOM
节点放入inputRef.current
中。但是,这取决于MyInput
组件是否允许这种行为, 默认情况下是不允许的。MyInput
组件是使用forwardRef
声明的。 这让从上面接收的inputRef
作为第二个参数ref
传入组件,第一个参数是props
。MyInput
组件将自己接收到的ref
传递给它内部的<input>
。
现在,单击按钮聚焦输入框起作用了:
通过命令句柄(
useImperativeHandle
)暴露一部分的 APIflushSync
同步更新 DOM:与Vue
中的nextTick
的用途类似,都是用来在 DOM 更改后进行某些操作,但Vue
是将该操作放在nextTick
的回调队列里面执行,包裹的是目的执行操作,而React
是让setState
同步更新 DOM。函数组件由于没有实例,不能使用
ref
获取,如果想获取组件实例,必须是类组件
useReducer
App.js
tasksReducer.js
useContext
常规使用
在相同的组件中提供并使用 context:
使用
Context
和Reducer
封装一个组件
useCallback
React
中的 useCallback
是一个用于缓存函数定义的 Hook
。它的作用是避免在每次重新渲染时都创建新的函数,从而提高性能和避免不必要的渲染。
useCallback
的使用方法如下:
useCallback
接收两个参数:回调函数和依赖项数组。回调函数是需要缓存的函数,依赖项数组用于确定何时需要重新创建函数实例。- 当依赖项数组中的任何一个值发生变化时,
useCallback
将返回一个新的函数实例,否则它将返回之前缓存的函数实例。 useCallback
返回的函数不会被React
调用,而是由你自己决定何时以及是否调用它。useCallback
必须在组件的顶层或自定义Hook
中调用,不能在循环或条件语句中调用。
useCallback
的使用场景有以下几种:
当你需要将一个函数作为
prop
传递给子组件时,你可以使用useCallback
来避免子组件因为父组件的重新渲染而不必要地重新渲染。例如,下面的代码展示了一个使用useCallback
的计数器组件,它将一个函数作为prop
传递给子组件Button
,用来增加计数器的值。由于使用了useCallback
,Button
组件只会在count
发生变化时才重新渲染,而不会因为父组件的其他state
变化而重新渲染。当你需要在一个
memoized
的回调函数中更新state
时,你可以使用useCallback
来保证回调函数的引用不变,从而避免触发无限循环。例如,下面的代码展示了一个使用useCallback
的自定义Hook
,用来获取和设置localStorage
中的数据。由于使用了useCallback
,setStoredValue
函数的引用不会在每次重新渲染时改变,从而避免在useEffect
中触发无限循环。当你需要在一个
useEffect
中使用一个函数时,你可以使用useCallback
来避免因为函数的重新创建而导致useEffect
的频繁执行。例如,下面的代码展示了一个使用useCallback
的组件,用来在组件挂载时获取用户的位置信息,并在用户位置发生变化时更新state
。由于使用了useCallback
,getLocation
函数的引用不会在每次重新渲染时改变,从而避免在useEffect
中触发不必要的执行。
useMemo
useMemo
是一个 React
钩子,它允许你记住函数调用的结果,并在依赖关系发生变化时重新计算它。它可以通过防止不必要的重渲染来优化 React
应用程序的性能。
useMemo
的基本语法是:
其中,第一个参数是一个函数,它返回需要被记住的值。第二个参数是一个数组,它指定了哪些变量会影响这个值的计算。如果这个数组为空,那么 useMemo
只会在组件第一次渲染时执行一次。如果这个数组包含了一些变量,那么 useMemo
只会在这些变量发生变化时重新执行。如果这个数组包含了所有的状态和属性,那么 useMemo
的行为就和普通的函数一样,每次渲染都会执行一次。
useMemo
的使用场景有以下几种:
- 当组件中有一些复杂的计算逻辑,而这些计算逻辑的结果又不会频繁地变化时,可以使用
useMemo
来缓存这些结果,避免每次渲染都重新计算,提高性能。 - 当组件中有一些子组件,而这些子组件的属性是由父组件的状态或属性计算而来时,可以使用
useMemo
来缓存这些属性,避免父组件的状态或属性发生变化时,导致子组件不必要的重渲染。 - 当组件中有一些引用类型的状态或属性,如对象或数组时,可以使用
useMemo
来缓存这些状态或属性,避免每次渲染都创建新的引用,导致组件的浅比较失效,引起不必要的重渲染。
下面是一个使用 useMemo
的例子,它展示了如何使用 useMemo
来缓存一个复杂的计算结果,并将其作为子组件的属性传递:
在这个例子中,当点击按钮时,数字状态会加 1
,父组件会重新渲染,但是由于使用了 useMemo
,只有当数字状态发生变化时,才会重新调用computeExpensiveValue
函数,否则会直接返回缓存的值。这样就避免了每次渲染都执行一个复杂的计算,提高了性能。同时,由于子组件的属性没有变化,所以子组件也不会重新渲染,这也提高了性能。