告别繁杂的状态管理:Zustand 的简洁之道

1. Zustand
Zustand 是一个轻量级的状态管理库,用于 JavaScript 应用程序,特别是在 React 生态系统中。它提供了一个简单、可扩展的解决方案来中心化和管理应用程序的状态。
与其他状态管理解决方案(如 Redux 或 MobX)相比,Zustand 旨在提供更简洁的 API 和更少的样板代码。它允许你创建一个全局状态存储,并且可以在应用程序的任何地方访问和更新这个状态,而不需要像 Redux 那样编写大量的 action creators 和 reducers。
Zustand 的主要特点包括:
- 简洁的 API:创建 store 和访问 state 都非常直观。
- React hooks:
Zustand与 React hooks 完美整合,使得在 React 组件中使用状态变得非常简单。 - 不可变更新:通过 Immer 库支持,
Zustand允许你以一种直观的方式更新复杂的状态对象。 - 中间件支持:可以使用中间件来添加额外的功能,例如日志记录、持久化等。
- 没有“单一真相来源”的限制:与 Redux 不同,
Zustand允许你创建多个独立的 store。
Zustand 是在 React 社区内广受欢迎的解决方案之一,适用于那些想要更简单状态管理工具的开发者。
2. 诞生背景
Zustand 是一个为 React 应用程序设计的简洁且实用的状态管理库。它的诞生背景和主要解决的问题如下:
背景
随着 React 应用程序的增长和复杂性的提升,开发者开始寻找更简单、更易于维护的状态管理解决方案。在 Zustand 出现之前,许多 React 项目使用 Redux 作为其主要的状态管理工具。Redux 有很多优点,比如可预测性、中心化状态和时间旅行调试功能,但是它也有一些缺点,比如:
- 重度依赖样板代码(action、reducer、selector 等)
- 学习曲线陡峭
- 对于小到中型的项目来说可能过于复杂
因此,社区开始探索其他的状态管理解决方案,目的是减少样板代码、简化开发流程,并提供与 React 更自然的集成。
解决的问题
Zustand 主要旨在解决以下问题:
-
简化状态管理:提供一个更直观的 API,通过避免 Redux 那样的冗余样板代码,使得状态管理更加简洁和直接。
-
更好的开发体验:通过使用 React Hooks,
Zustand使得在函数组件中访问和更新状态变得容易。 -
无拘无束:
Zustand允许创建多个独立的 store,不强制要求"单一真相来源",给予开发者更多的灵活性。 -
性能优化:
Zustand允许组件仅订阅状态的一部分,从而减少不必要的渲染和提高性能。 -
简单的状态共享:不需要复杂的上下文或提供者,状态可以跨组件和文件轻松共享。
-
中间件和增强功能:支持中间件,使得开发者可以轻松添加日志记录、持久化存储等增强功能。
-
适应现代 React 功能:考虑到了 React 的新特性,如 Concurrent Mode 和 Suspense,从而确保在现代 React 特性下的稳定性。
总之,Zustand 应运而生,旨在为开发者提供一个轻便、简单且功能强大的状态管理库,让状态管理变得更加易于使用和维护。
3. React 陷阱
在 React 应用程序中,有几个常见的问题可能会给开发者带来挑战:
- Zombie Child Problem (僵尸子组件问题): 这个问题发生在 React 的异步渲染环境中,尤其是在使用 Concurrent Mode 时。当一个 React 组件的状态更新后,子组件可能会在一个渲染周期中引用旧的父组件状态。这意味着子组件表现得好像它们“僵死”在了一个过时的状态上,与当前的应用程序状态不同步。
function Parent() {const [count, setCount] = useState(0);return (<><button onClick={() => setCount((c) => c + 1)}>Increment</button><Child count={count} /></>);
}function Child({ count }) {const [childCount, setChildCount] = useState(count);useEffect(() => {// 假设这个 effect 是基于某种条件或异步操作触发的,我们这里直接模拟setChildCount(count);}, [count]); // 依赖于父组件的 countreturn <div>Child Count: {childCount}</div>;
}
在 Concurrent Mode 下,如果 Parent 组件多次快速更新,而 Child 组件的 useEffect 更新延迟或者因为某些原因未能及时执行,Child 组件可能会显示一个过时的 count 值。
- React Concurrency (React 并发问题):React 16.8 引入了 Concurrent Mode,它带来了新的并发功能,可以让 React 在渲染过程中中断和恢复工作。这种能力提高了应用的响应性和性能,但同时也引入了复杂性,因为开发者需要确保他们的状态管理能够适应可能出现的中断和重新开始的渲染。
function MyComponent() {const [value, setValue] = useState(0);// 假设 performAsyncOperation 是一个异步操作async function performAsyncOperation() {// 这个操作可能被中断,如果在完成之前有其他更高优先级的渲染任务发生const result = await someAsyncOperation();setValue(result);}useEffect(() => {performAsyncOperation();}, []);return <div>{value}</div>;
}
在这个场景中,someAsyncOperation 可能被中断,如果 React 在此期间开始了一个新的渲染任务,这可能会引起复杂的状态问题。
- Context Loss Between Mixed Renderers (混合渲染器之间的上下文丢失问题):当你在同一个应用程序中混合使用不同类型的渲染器(例如,同时使用 ReactDOM 和 React Native 或者 SSR 与客户端渲染)时,可能会遇到上下文丢失的问题。这是因为 React 的上下文机制是按渲染器实例进行隔离的。如果状态管理库不正确地处理这些情况,可能会导致跨不同渲染器的组件状态不一致。
import React from "react";
import ReactDOM from "react-dom";
import SomeLibrary from "some-library";const MyContext = React.createContext();function App() {return (<MyContext.Provider value={{ someValue: "value" }}><SomeLibraryComponent /></MyContext.Provider>);
}function SomeLibraryComponent() {// 假设 SomeLibrary 使用了不同的渲染器或者以某种方式改变了渲染上下文const contextValue = useContext(MyContext);// 这里可能无法获取到期望的上下文,因为 SomeLibrary 可能已经切换了上下文环境return <div>{contextValue.someValue}</div>;
}ReactDOM.render(<App />, document.getElementById("root"));
在这个示例中,如果 SomeLibraryComponent 不正确地处理上下文,那么它可能无法访问到由 MyContext.Provider 提供的值。
解决这些问题通常涉及到深入的 React 知识和对状态管理库的细致设计。例如,Zustand 在其实现中考虑到了这些潜在问题,并提供了一套机制来避免它们,以确保状态的一致性和应用的稳定性。
4. Zustand VS 其他状态库
下面是一个表格形式来对比 Zustand 和其他几个状态管理库的关键方面:
Zustand vs Redux
| 特性 | Zustand | Redux |
|---|---|---|
| 状态模型 | 不可变状态 | 不可变状态 |
| Context | 不需要 | 需要使用 Provider |
| API | 简洁 | 标准 Redux 需要 action、reducer;Redux Toolkit 提供简化的 API |
| 代码样板 | 较少 | 较多(尽管 Redux Toolkit 有所简化) |
| 渲染优化 | 手动使用选择器 | 手动使用选择器(Redux Toolkit 中 selector 的使用更为普遍) |
| 状态更新 | 直接通过 store 函数 | 通过 dispatch 和 reducer |
| 中间件支持 | 有支持 | 有支持,中间件生态丰富 |
| 其他 | 无需包装应用,易于集成 | 广泛的社区和生态系统支持,适合大型应用 |
Zustand vs Valtio
| 特性 | Zustand | Valtio |
|---|---|---|
| 状态模型 | 不可变状态 | 可变状态 |
| Context | 不需要 | 不需要 |
| API | 简洁 | 直接修改状态 |
| 代码样板 | 较少 | 几乎无 |
| 渲染优化 | 手动使用选择器 | 通过属性访问自动优化 |
| 状态更新 | 通过 set 函数以不可变方式更新状态 | 直接对状态对象进行可变更新 |
| 中间件支持 | 有支持 | 不适用(因为是可变的,无需额外的 Immer 等对不可变的处理) |
| 其他 | 易于集成 | 易于理解和使用,特别是对于习惯可变数据模式的开发者 |
Zustand vs Jotai
| 特性 | Zustand | Jotai |
|---|---|---|
| 状态模型 | 不可变状态 | 原子状态(可组合的小单位状态) |
| Context | 不需要 | 不需要 |
| API | 直观、简洁 | 细粒度、可组合 |
| 代码样板 | 较少 | 较少 |
| 渲染优化 | 手动使用选择器 | 原子依赖自动优化 |
| 状态更新 | 直接通过 store 函数 | 使用原子更新和订阅状态 |
| 中间件支持 | 有支持 | 不适用(原子模型提供不同的扩展方式) |
| 其他 | 易于集成 | 原子模型提供更高的可组合性,适用于需要细粒度状态管理的场景 |
Zustand vs Recoil
| 特性 | Zustand | Recoil |
|---|---|---|
| 状态模型 | 不可变状态 | 原子状态(通过字符串键识别) |
| Context | 不需要 | 需要用 RecoilRoot 包装 |
| API | 直观、简洁 | 细粒度、可组合,但需要理解 Recoil 的概念 |
| 代码样板 | 较少 | 适中(需要定义原子和选择器) |
| 渲染优化 | 手动使用选择器 | 原子和选择器依赖自动优化 |
| 状态更新 | 直接通过 store 函数 | 使用原子和选择器进行状态更新和订阅 |
| 中间件支持 | 有支持 | 不适用(Recoil 提供不同的扩展方式) |
| 其他 | 易于集成 | 提供更为高级的状态同步和派生功能,适用于复杂状态逻辑的应用 |
5. 安装
要在你的 React 项目中安装和使用 Zustand,你需要遵循以下步骤:
步骤 1: 安装 Zustand
使用 npm 或 yarn 来安装 Zustand:
# 使用 npm
npm install zustand# 使用 yarn
yarn add zustand
步骤 2: 创建你的第一个 store
创建一个新文件(例如 store.js)来定义你的 store 和 state。使用 create 方法来创建一个新的 store。
// store.js
import create from "zustand";const useStore = create((set) => ({bears: 0,increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),removeAllBears: () => set({ bears: 0 }),
}));export default useStore;
在这个例子中,我们创建了一个包含熊的数量和两个改变数量的方法的简单 store。
步骤 3: 在你的组件中使用 store
现在可以在你的 React 组件中使用定义好的 store 了。
// App.js
import React from "react";
import useStore from "./store";function App() {const bears = useStore((state) => state.bears);const increasePopulation = useStore((state) => state.increasePopulation);const removeAllBears = useStore((state) => state.removeAllBears);return (<div><h1>{bears} around here...</h1><button onClick={increasePopulation}>Add a bear</button><button onClick={removeAllBears}>Remove all bears</button></div>);
}export default App;
在这个组件中,我们通过调用 useStore 并传入选择器函数来访问 store 中的 bears、increasePopulation 和 removeAllBears。
步骤 4: 运行你的应用
你现在可以运行你的应用来查看 Zustand 状态管理是如何工作的。
# 如果你使用 npm
npm start# 如果你使用 yarn
yarn start
你的应用将启动,并且你可以看到熊的数量,并使用按钮来增加或者移除熊。
6. 使用技巧
function BearCounter() {const bears = useBearStore((state) => state.bears)return <h1>{bears} around here ...</h1>
}function Controls() {const increasePopulation = useBearStore((state) => state.increasePopulation)return <button onClick={increasePopulation}>one up</button>
}
获取所有内容
你可以获取整个 store,但请记住这样做会导致组件在每次状态变化时都重新渲染!
const state = useBearStore();
选择多个状态片段
默认情况下,Zustand 使用严格相等(old === new)来检测变化,这对于原子状态选择是高效的。
const nuts = useBearStore((state) => state.nuts);
const honey = useBearStore((state) => state.honey);
如果你想构造一个包含多个状态选择的单个对象,类似于 Redux 的 mapStateToProps,你可以使用 useShallow 来防止当选择器输出根据浅相等不变时不必要的重新渲染。
import { create } from "zustand";
import { useShallow } from "zustand/react/shallow";const useBearStore = create((set) => ({bears: 0,increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),removeAllBears: () => set({ bears: 0 }),
}));const { nuts, honey } = useBearStore(useShallow((state) => ({ nuts: state.nuts, honey: state.honey })),
);
覆盖状态
set 函数有第二个参数,默认为 false。而不是合并,它将替换状态模型。小心不要抹去你依赖的部分,如操作。
import omit from "lodash-es/omit";const useFishStore = create((set) => ({salmon: 1,tuna: 2,deleteEverything: () => set({}, true), // 清除整个 store,包括操作deleteTuna: () => set((state) => omit(state, ["tuna"]), true),
}));
异步操作
当你准备好时,只需调用 set,zustand 不介意你的操作是异步的还是同步的。
const useFishStore = create((set) => ({fishies: {},fetch: async (pond) => {const response = await fetch(pond);set({ fishies: await response.json() });},
}));
在操作中读取状态
set 允许函数更新 set(state => result),但你依然可以通过 get 在外部访问状态。
const useSoundStore = create((set, get) => ({sound: "grunt",action: () => {const sound = get().sound;// ...},
}));
在组件外部读写状态和响应变化
有时你需要以非响应式的方式访问状态或对 store 进行操作。对于这些情况,结果钩子有附加到其原型的实用程序函数。
const useDogStore = create(() => ({ paw: true, snout: true, fur: true }));const paw = useDogStore.getState().paw; // 获取非响应式最新状态
const unsub1 = useDogStore.subscribe(console.log); // 监听所有变化
useDogStore.setState({ paw: false }); // 更新状态,触发监听器
unsub1(); // 取消订阅监听器
使用带选择器的订阅
如果你需要使用选择器订阅,subscribeWithSelector 中间件会有所帮助。
import { subscribeWithSelector } from "zustand/middleware";const useDogStore = create(subscribeWithSelector(() => ({ paw: true, snout: true, fur: true })),
);const unsub2 = useDogStore.subscribe((state) => state.paw, console.log);
在没有 React 的情况下使用 zustand
Zustand 核心可以导入并在没有 React 依赖的情况下使用。唯一的区别是 create 函数不返回一个钩子,而是 API 实用程序。
import { createStore } from 'zustand/vanilla';const store = createStore((set) => ...);
const { getState, setState, subscribe, getInitialState } = store;
export default store;
中间件
你可以按照你喜欢的方式函数组合你的 store。
// 每次状态变化时记录日志的中间件
const log = (config) => (set, get, api) => config(...);
const useBeeStore = create(log((set) => ({ bees: false })));
Redux 开发者工具
import { devtools } from 'zustand/middleware';const usePlainStore = create(devtools((set) => ...)); // 使用了 Redux 开发者工具的 store
7. 重新渲染?
Zustand 库使用了选择器 (selectors) 函数和引用相等性 (reference equality) 检查来帮助避免无效渲染。当你在组件中使用 Zustand 的 useStore 钩子时,你可以提供一个选择器函数来订阅特定的状态片段。Zustand 会使用严格相等性检查 (===) 来比较选择器返回的状态片段是否真的发生了变化,如果状态片段的值没有变化,组件不会重新渲染。
例如:
const bears = useStore((state) => state.bears);
在这个例子中,组件只订阅 bears 状态片段,如果 bears 值没有变化,即使其他状态改变,组件也不会重新渲染。
对于更复杂的状态选择,可能需要构造一个包含多个状态片段的对象,这时可以使用 shallow 比较来防止无效渲染:
import { useShallow } from "zustand/shallow";const { nuts, honey } = useStore((state) => ({nuts: state.nuts,honey: state.honey,}),useShallow,
);
useShallow 是从 Zustand 提供的 /shallow 路径中导入的一个工具函数,它对返回的对象进行浅层比较,如果对象的顶层属性和之前的状态一样,即使引用不同,也不会重新渲染组件。
总结一下,Zustand 通过以下方式来避免无效渲染:
- 选择器:通过允许你订阅特定的状态片段,仅当这些片段发生变化时才触发组件的重新渲染。
- 引用相等性检查:默认情况下,选择器返回的状态片段会通过严格相等性检查来决定是否需要重新渲染。
- 浅层比较:使用
useShallow或其他浅层比较函数来对选择器返回的对象进行浅层属性比较,从而进一步减少不必要的渲染。
这些方法在一定程度上可以优化渲染性能,确保仅在实际需要时才更新组件。

微信搜索“好朋友乐平”关注公众号。
github原文地址
相关文章:
告别繁杂的状态管理:Zustand 的简洁之道
1. Zustand Zustand 是一个轻量级的状态管理库,用于 JavaScript 应用程序,特别是在 React 生态系统中。它提供了一个简单、可扩展的解决方案来中心化和管理应用程序的状态。 与其他状态管理解决方案(如 Redux 或 MobX)相比&…...
CentOS磁盘扩容
参考操作 检查磁盘扩容情况 lsblk 使用fdisk命令进行开垦,有时需要重启之后才能进行下一步 fdisk /dev/新盘mkfs.ext4 /dev/新盘使用pvcreate直接创建虚拟卷 pvcreate /dev/新盘使用vgextend添加新创建的虚拟卷 vgextend 卷名称 /dev/新盘使用lvextend进行扩容…...
【数据分享】1929-2023年全球站点的逐日降雪深度数据(Shp\Excel\免费获取)
气象数据是在各项研究中都经常使用的数据,气象指标包括气温、风速、降水、能见度等指标,说到气象数据,最详细的气象数据是具体到气象监测站点的数据! 之前我们分享过1929-2023年全球气象站点的逐日平均气温数据、逐日最高气温数据…...
golang网络编程day4
golang网络编程day4 get和post的区别resful编程golang请求头golangheader内容类型和字符编码http请求头缓存和过期应用golang 请求头跨域请求应用http请求头用户代理应用golang响应头 get和post的区别 在前面的学习我只在应用场景上做了一个区别的举例,这里是进一步的学习有哪…...
为什么pgsql(内关联查询或者with字句时)会导致索引失效
1、在PostgreSQL中,内关联查询可能导致索引失效的原因通常与查询的过滤条件和数据分布有关。 以下是一些可能导致索引失效的情况: 1、使用了函数或类型转换:当查询条件中对索引字段使用了任何计算、函数或类型转换时,这可能会阻止…...
小程序 自定义组件和生命周期
文章目录 ⾃定义组件创建⾃定义组件声明组件编辑组件注册组件 声明引⼊⾃定义组件⻚⾯中使⽤⾃定义组件定义段与⽰例⽅法组件-⾃定义组件传参过程 小程序生命周期应用生命周期页面生命周期页面生命周期 ⾃定义组件 类似vue或者react中的自定义组件 ⼩程序允许我们使⽤⾃定义组件…...
asp.net 404页面配置、 asp.net MVC 配置404页面、iis 配置404页面,指定404错误页面,设置404错误页面
通过标题的三个问题 1、asp.net 404页面配置、 2、asp.net MVC 配置404页面、 3、iis 配置404页面; 可以看出,这是一篇了不得的问题,并进行全面讲解; 除了围绕以上三个核心问题外,我们也对以下2个核心场景也作出分析…...
Docker存储空间清理
不知不觉服务器存储空间被Docker掏空了… 查看Docker空间占用情况 使用docker system df命令,可以加 -v 查看详情 清理Docker不需要的内容 使用docker system prune -a命令清理Docker 所有停止的容器所有没有被使用的networks所有没容器的镜像所有build cache …...
React16源码: React中NewContext的源码实现
NewContext 1 )概述 新的 context API 是一个组件化的使用方式 它就跟写其他的组件一样,像写jsx,通过标签的这种方式来赋值一些props还有去给子节点去拿到这个 conntext 的属性 context的提供方和订阅方都是独立的 在什么地方想要用到这个 c…...
【Linux】【Shell】常用压缩和解压缩命令(超详细)
目录 1. 指令: 1.1 tar 1.2 gz、.tar.gz 1.3 .bz2、.tar.bz2、.bz 1.4 .z、.tar.z 1.5 .zip 1.6 .rar 1.7 lzop 2. 示例: 1. 指令: 快速压缩:XZ_DEFAULTS"-T0" tar cJvf xxxxx.tar.xz sourcefile(压…...
【Java程序设计】【C00232】基于Springboot的抗疫物资管理系统(有论文)
基于Springboot的抗疫物资管理系统(有论文) 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于Springboot的抗疫物资管理系统 用户主要分为管理员和普通用户 管理员: 管理员可以对后台数据进行管理、拥有最高权限、具体权限有…...
2023年全球软件开发大会(QCon上海站2023):核心内容与学习收获(附大会核心PPT下载)
在信息化和全球化日益加速的今天,软件开发技术日新月异,对全球各行各业产生了深远影响。2023年全球软件开发大会(QCon上海站2023)无疑成为行业内外瞩目的焦点。本次大会汇集了全球顶级的软件开发专家、企业领袖、研究者࿰…...
【Linux】Ext2 文件系统
文件系统 前言一、磁盘硬件1. 磁盘的物理存储结构2. 磁盘存储的逻辑抽象结构 二、理解 Ext2 文件系统1. 初步理解文件系统2. 深入理解文件系统(1)inode Table(2)Data blocks(3)inode Bitmap(4&a…...
studyNote-linux-shell-find-examples
前言:本文的例子均来源于man手册第一章节的find,man 1 find查看 e.g.01 手册原文: find /tmp -name core -type f -print | xargs /bin/rm -fFind files named core in or below the directory /tmp and delete them. Note that this will work incor…...
使用 Python 进行自然语言处理第 3 部分:使用 Python 进行文本预处理
一、说明 文本预处理涉及许多将文本转换为干净格式的任务,以供进一步处理或与机器学习模型一起使用。预处理文本所需的具体步骤取决于具体数据和您手头的自然语言处理任务。 常见的预处理任务包括: 文本规范化——将文本转换为标准表示形式,…...
Python新春烟花盛宴
写在前面 哈喽小伙伴们,博主在这里提前祝大家新春快乐呀!我用Python绽放了一场新春烟花盛宴,一起来看看吧! 环境需求 python3.11.4及以上PyCharm Community Edition 2023.2.5pyinstaller6.2.0(可选,这个库…...
【QT+QGIS跨平台编译】之二十:【xerces+Qt跨平台编译】(一套代码、一套框架,跨平台编译)
文章目录 一、xerces介绍二、文件下载三、文件分析四、pro文件五、编译实践一、xerces介绍 Xerces是一个开源的XML解析器,由Apache软件基金会维护。它是用Java语言编写的,提供了对XML文档进行解析、验证和操作的功能。Xerces具有高性能和广泛的兼容性,可用于各种Java应用程…...
18.通过telepresence调试部署在Kubernetes上的微服务
Telepresence简介 在微服务架构中,本地开发和调试往往是一项具有挑战性的任务。Telepresence 是一种强大的工具,使得开发者本地机器上开发微服务时能够与运行在 Kubernetes 集群中的其他服务无缝交互。本文将深入探讨 Telepresence 的架构、运行原理,并通过实际的案例演示其…...
QT 范例阅读:系统托盘 The System Tray Icon example
main.cpp QApplication app(argc, argv);//判断系统是否支持 系统托盘功能if (!QSystemTrayIcon::isSystemTrayAvailable()) {QMessageBox::critical(0, QObject::tr("Systray"),QObject::tr("I couldnt detect any system tray ""on this system.&qu…...
OpenAI Gym 高级教程——深度强化学习库的高级用法
Python OpenAI Gym 高级教程:深度强化学习库的高级用法 在本篇博客中,我们将深入探讨 OpenAI Gym 高级教程,重点介绍深度强化学习库的高级用法。我们将使用 TensorFlow 和 Stable Baselines3 这两个流行的库来实现深度强化学习算法ÿ…...
HTML 语义化
目录 HTML 语义化HTML5 新特性HTML 语义化的好处语义化标签的使用场景最佳实践 HTML 语义化 HTML5 新特性 标准答案: 语义化标签: <header>:页头<nav>:导航<main>:主要内容<article>&#x…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
深入浅出:JavaScript 中的 `window.crypto.getRandomValues()` 方法
深入浅出:JavaScript 中的 window.crypto.getRandomValues() 方法 在现代 Web 开发中,随机数的生成看似简单,却隐藏着许多玄机。无论是生成密码、加密密钥,还是创建安全令牌,随机数的质量直接关系到系统的安全性。Jav…...
解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习
禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...
AI病理诊断七剑下天山,医疗未来触手可及
一、病理诊断困局:刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断",医生需通过显微镜观察组织切片,在细胞迷宫中捕捉癌变信号。某省病理质控报告显示,基层医院误诊率达12%-15%,专家会诊…...
