css visible
属性(display还是content-visibility ? )来控制需要保存状态组件的渲染,而不是使用 if/else
,避免React将其卸载。React-Router
二次开发。React-Router
在路由切换时默认卸载非活动组件,因此这些库通过重写 React-Router
中的部分功能或者将其拓展的方式使得在路由切换时相关组件不被直接卸载,而是缓存下来。这种实现方式决定了状态保存的粒度只能具体到SPA的页面级别。strict mode
的回复中提到了其正在开发的 <Offscreen>
组件,并且预计其在 react@18.X
(非18早期版本)中可能会出现,其功能与vue <keep-alive>
类似。react-router-cache-route
。react-activation
。此外umi中使用 react-activation
可以直接使用其封装插件 umi-plugin-keep-alive
。如:
// a.tsx
// 箭头函数添加泛型报错(Error: JSX element ‘T’ has no corresponding closing tag.ts(17008))
const foo = <T>(props: T)=> void
原因: 因为泛型的语法与 JSX 的语法冲突,导致 TS 解析成 JSX 而产生 unexpected token 的问题
解决:
1. 不要写在 .tsx 文件里面就不会报错
2. 在后面加一个逗号就能正确解析了
3.
const foo = <T,>(props: T)=> void
React.ComponentProps<typeof Button>
ConstructorParameters :类构造函数参数类型的元组
Exclude:将一个类型从另一个类型排除
Extract:选择可分配给另一类型的子类型
InstanceType:从一个新类构造函数中获得的实例类型
NonNullable:从类型中排除空和未定义
Parameters:函数的形参类型的元组
Partial:使对象中的所有属性都是可选的
Readonly:将对象中的所有属性设置为只读
ReadonlyArray:创建给定类型的不可变数组
Pick:对象类型的一种子类型,包含其键的子集
Record:从键类型到值类型的映射
Required:使对象中的所有属性都是必需的
ReturnType:函数的返回类型
当我们将某个变量定义为 any
类型后,TypeScript
将会跳过对这个变量的类型检查
TypeScript
在3.0版本引入了 unknown
类型,它可以理解为类型安全的 (type-safe)any
unknown
类型的对象unknown
类型的对象不可以直接赋值给其它非 unknown
或 any
类型的对象,并且不可以访问上面的任何属性never
就是 TypeScript
的底部类型
never
类型只接受 never
类型的对象, any
也不接受never
会从联合类型中移除,类似于将零和其他数字相加时结果等于该数字。即 type Res = never | string // string
never
会覆盖交叉类型中的其他类型,类似于零乘其他数字时结果等于零。即 type Res = never & string // never
void
其实可以理解为 null
和 undefined
的联合类型,它表示空值
1.循环遍历出最深层子节点,存放在一个数组中
2.将后台返回的含有父节点的数组和第一步骤遍历的数组做比较
3.如果有相同值,将相同值取出来,push到一个新数组中
4.利用这个新的重组的数组给Tree组件selected赋值
const deepArr = [] //deepArr存放所有子节点的数组
//第一步骤:子节点放在一个数组中
const requestList = (data) => {
data && data.map(item => {
if (item.children && item.children.length > 0) {
requestList(item.children)
} else {
deepArr.push(item.id)
}
return null
})
return deepArr
}
//第2,3步骤的方法
const uniqueTree = (uniqueArr, Arr) => {
let uniqueChild = []
for (var i in Arr) {
for (var k in uniqueArr) {
if (uniqueArr[k] === Arr[i]) {
uniqueChild.push(uniqueArr[k])
}
}
}
return uniqueChild
}
//调用第2,3步骤的方法
const getRoleInfo = () => {
getData({ id: Id }).then(res => {
const ids = res.data
const uniqueChild = this.uniqueTree(ids, deepArr)
setCheckedKeys(uniqueChild)
})
}
<Tree
checkable
checkedKeys={checkedKeys}
defaultExpandedKeys={checkedKeys}
fieldNames={{
git submodule
子模块允许你将一个 Git 仓库作为另一个 Git 仓库的子目录。 它能让你将另一个仓库克隆到自己的项目中,同时还保持提交的独立。
比如我们想抽象出一个组件库供多个项目使用
git submodule add <子模块git地址> <存放的文件名>
会生成: .gitmodules 和 子模块文件夹
.gitmodules 文件保存了项目 URL 与已经拉取的本地目录之间的映射,这样就能知道子模块在哪获取。如果有多个子模块,该文件中就会有多条记录。
子模块文件夹只存子项目的commit id,就能指定到对于的git header上, 父项目的git并不会记录Submodule的文件变动,它是按照commitid指定Submodule的git header
当你不在那个目录中时,Git 并不会跟踪它的内容, 而是将它看作子模块仓库中的某个具体的提交。
注意的是,这两个文件也像 .gitignore 文件一样受到(通过)版本控制。 它会和该项目的其他部分一同被拉取推送。
克隆含有子模块的项目
克隆一个含有子模块的项目时,默认会包含该子模块目录,但其中还没有任何文件,是空目录。 必须运行:
git submodule init 用来初始化本地配置文件
git submodule update 则从该项目中抓取所有数据并检出父项目中列出的合适的提交。
合成一步就是: git submodule update --init
如果还要初始化、抓取并检出任何嵌套的子模块:git submodule update --init --recursive
或者在克隆的时候加上参数: git clone --recurse-submodules
它就会自动初始化并更新仓库中的每一个子模块, 包括可能存在的嵌套子模块。
修改submodule
进入submodule目录里修改后add 、commit 、push到远程服务器,然后要回到父目录,提交submodule在父项目中的改动(submodule commit id 会更新),再push
坑:子模块的分支默认不是master,也不会切到任何branch