React 状态丢失:组件 key 用错引发的渲染异常
Hello,我是摘星!
在彩虹般绚烂的技术栈中,我是那个永不停歇的色彩收集者。
每一个优化都是我培育的花朵,每一个特性都是我放飞的蝴蝶。
每一次代码审查都是我的显微镜观察,每一次重构都是我的化学实验。
在编程的交响乐中,我既是指挥家也是演奏者。让我们一起,在技术的音乐厅里,奏响属于程序员的华美乐章。
目录
React 状态丢失:组件 key 用错引发的渲染异常
摘要
1. React Key 机制深度解析
1.1 Virtual DOM Diff 算法核心
1.2 Key 的三种使用模式
2. 常见的 Key 使用陷阱
2.1 数组索引陷阱:状态错位的根源
2.2 动态Key生成陷阱
3. 状态丢失的典型场景分析
3.1 列表重排序场景
3.2 条件渲染场景
4. 高级场景的 Key 策略
4.1 嵌套列表的Key设计
4.2 动态表单的Key管理
5. Key 最佳实践与性能优化
5.1 Key 选择的优先级策略
5.2 性能监控与调试
6. 实战案例:电商商品列表优化
7. 调试工具与开发技巧
7.1 React DevTools 中的 Key 调试
7.2 自动化Key验证
8. 性能对比与测试结果
9. 常见问题与解决方案
9.1 FAQ 快速解答
9.2 迁移指南
10. 未来发展与新特性
10.1 React 18+ 的Key优化
10.2 未来的Key管理工具
总结
参考链接
关键词标签
摘要
作为一名在前端战场摸爬滚打多年的老兵,我深知React开发中那些看似微不足道的细节往往能引发惊天动地的bug。今天要和大家分享的,是一个让我在深夜调试时几乎抓狂的问题——组件key使用不当导致的状态丢失。这个问题的隐蔽性极强,往往在你以为一切都完美运行时突然跳出来给你一记重拳。
在我最近的一个项目中,用户反馈说表单数据会莫名其妙地消失,输入框的内容会突然变成其他用户的数据,列表项的展开状态会错乱。起初我以为是状态管理的问题,花了大量时间检查Redux的action和reducer,甚至怀疑是不是服务端数据有问题。直到我深入分析React的渲染机制,才发现罪魁祸首竟然是那个看起来人畜无害的key属性。
React的key属性是Virtual DOM diff算法的核心依据,它决定了React如何识别和复用组件实例。当key使用不当时,React会错误地复用组件实例,导致状态在不应该保持的时候被保持,在应该保持的时候被重置。这种问题在动态列表、条件渲染、路由切换等场景中尤为常见,而且往往只在特定的用户操作序列下才会触发,让人防不胜防。
通过这篇文章,我将带你深入理解React key的工作原理,剖析各种错误使用方式的根本原因,并提供一套完整的最佳实践方案。我们会从简单的列表渲染开始,逐步深入到复杂的嵌套组件、动态表单、路由切换等高级场景。每个案例都会配备详细的代码示例和可视化图表,让你能够直观地理解问题的本质和解决方案的精髓。
1. React Key 机制深度解析
1.1 Virtual DOM Diff 算法核心
React的diff算法是其高性能的关键所在,而key属性则是这个算法的指挥棒。让我们先通过一个流程图来理解React是如何使用key进行组件对比的:
1.2 Key 的三种使用模式
React中key的使用可以分为三种模式,每种都有其适用场景和潜在陷阱:
// 模式1:数组索引作为key(危险)
function BadKeyExample({ items }) {
return (
{items.map((item, index) => (
))}
);
}
// 模式2:稳定唯一标识作为key(推荐)
function GoodKeyExample({ items }) {
return (
{items.map((item) => (
))}
);
}
// 模式3:组合key(复杂场景)
function ComplexKeyExample({ categories }) {
return (
{categories.map((category) => (
{category.name}
{category.items.map((item) => (
))}
))}
);
}
上述代码展示了三种不同的key使用方式。第一种使用数组索引是最危险的,当数组顺序发生变化时会导致严重的状态错乱。第二种使用稳定的唯一标识是最推荐的方式。第三种组合key适用于嵌套结构,确保在复杂场景下的唯一性。
2. 常见的 Key 使用陷阱
2.1 数组索引陷阱:状态错位的根源
使用数组索引作为key是最常见也是最危险的错误。让我们通过一个具体的例子来看看这会引发什么问题:
// 问题代码:使用索引作为key
function TodoList({ todos, onToggle, onDelete }) {
const [editingIndex, setEditingIndex] = useState(-1);
const [editText, setEditText] = useState('');
return (
{todos.map((todo, index) => (onToggle(index)}
/>
{editingIndex === index ? (setEditText(e.target.value)}
onBlur={() => setEditingIndex(-1)}
autoFocus
/>
) : ({
setEditingIndex(index);
setEditText(todo.text);
}}
>
{todo.text}
)}
))}
);
}
当用户删除列表中间的某一项时,由于索引重新分配,React会错误地复用组件实例,导致编辑状态和输入框内容出现错位。
2.2 动态Key生成陷阱
另一个常见错误是在渲染过程中动态生成key,这会导致每次渲染都创建新的组件实例:
// 错误:每次渲染都生成新的key
function DynamicKeyBad({ items }) {
return (
{items.map((item) => (
))}
);
}
// 正确:使用稳定的key
function DynamicKeyGood({ items }) {
return (
{items.map((item) => (
))}
);
}
3. 状态丢失的典型场景分析
3.1 列表重排序场景
在可拖拽排序的列表中,使用索引作为key会导致严重的状态混乱:
// 问题场景:可排序的表单列表
function SortableFormList({ fields, onReorder }) {
const [formData, setFormData] = useState({});
const handleInputChange = (index, value) => {
setFormData(prev => ({
...prev,
[index]: value
}));
};
return (
{fields.map((field, index) => (
{field.label}handleInputChange(index, e.target.value)}
placeholder={field.placeholder}
/>
))}
);
}
// 解决方案:使用稳定的field ID
function SortableFormListFixed({ fields, onReorder }) {
const [formData, setFormData] = useState({});
const handleInputChange = (fieldId, value) => {
setFormData(prev => ({
...prev,
[fieldId]: value
}));
};
return (
{fields.map((field) => (
{field.label}handleInputChange(field.id, e.target.value)}
placeholder={field.placeholder}
/>
))}
);
}
3.2 条件渲染场景
在条件渲染中,相同位置的不同组件如果没有合适的key,会导致状态被错误保留:
// 问题:条件渲染时状态保留
function ConditionalRender({ userType }) {
return (
{userType === 'admin' ? (
) : userType === 'user' ? (
) : (
)}
);
}
// 解决方案:为不同组件添加key
function ConditionalRenderFixed({ userType }) {
return (
{userType === 'admin' ? (
) : userType === 'user' ? (
) : (
)}
);
}
下面的时序图展示了条件渲染时组件的生命周期:
4. 高级场景的 Key 策略
4.1 嵌套列表的Key设计
在复杂的嵌套结构中,key的设计需要考虑多层级的唯一性:
// 复杂嵌套结构的key设计
function NestedListComponent({ categories }) {
const [expandedCategories, setExpandedCategories] = useState(new Set());
const [selectedItems, setSelectedItems] = useState(new Set());
const toggleCategory = (categoryId) => {
setExpandedCategories(prev => {
const newSet = new Set(prev);
if (newSet.has(categoryId)) {
newSet.delete(categoryId);
} else {
newSet.add(categoryId);
}
return newSet;
});
};
const toggleItem = (itemId) => {
setSelectedItems(prev => {
const newSet = new Set(prev);
if (newSet.has(itemId)) {
newSet.delete(itemId);
} else {
newSet.add(itemId);
}
return newSet;
});
};
return (
{categories.map((category) => (toggleCategory(category.id)}
>
{expandedCategories.has(category.id) ? '▼' : '▶'}
{category.name}
({category.items.length})
{expandedCategories.has(category.id) && (
{category.items.map((item) => (toggleItem(item.id)}
>toggleItem(item.id)}
/>
{item.name}
{item.description}
))}
)}
))}
);
}
4.2 动态表单的Key管理
动态表单是key使用最复杂的场景之一,需要处理字段的增删改查:
// 动态表单的完整key管理方案
function DynamicForm({ initialFields = [] }) {
const [fields, setFields] = useState(initialFields);
const [formData, setFormData] = useState({});
const [fieldIdCounter, setFieldIdCounter] = useState(0);
// 添加新字段
const addField = (type) => {
const newField = {
id: `field_${fieldIdCounter}`,
type,
label: `新字段 ${fieldIdCounter + 1}`,
required: false,
options: type === 'select' ? ['选项1', '选项2'] : undefined
};
setFields(prev => [...prev, newField]);
setFieldIdCounter(prev => prev + 1);
};
// 删除字段
const removeField = (fieldId) => {
setFields(prev => prev.filter(field => field.id !== fieldId));
setFormData(prev => {
const newData = { ...prev };
delete newData[fieldId];
return newData;
});
};
// 更新字段配置
const updateField = (fieldId, updates) => {
setFields(prev => prev.map(field =>
field.id === fieldId ? { ...field, ...updates } : field
));
};
// 更新表单数据
const updateFormData = (fieldId, value) => {
setFormData(prev => ({
...prev,
[fieldId]: value
}));
};
return (
表单构建器
表单预览
{fields.map((field) => (updateField(field.id, { label: e.target.value })}
placeholder="字段标签"
/>updateField(field.id, { required: e.target.checked })}
/>
必填
{field.label}
{field.required && *}
{renderFieldInput(field, formData[field.id], (value) => updateFormData(field.id, value))}
))}
);
}
// 渲染不同类型的表单输入
function renderFieldInput(field, value, onChange) {
switch (field.type) {
case 'text':
return (onChange(e.target.value)}
required={field.required}
/>
);
case 'textarea':
return (onChange(e.target.value)}
required={field.required}
rows={3}
/>
);
case 'select':
return (onChange(e.target.value)}
required={field.required}
>
请选择
{field.options?.map((option, index) => (
{option}
))}
);
case 'checkbox':
return (onChange(e.target.checked)}
/>
);
default:
return null;
}
}
5. Key 最佳实践与性能优化
5.1 Key 选择的优先级策略
选择合适的key需要遵循一定的优先级原则:
5.2 性能监控与调试
为了确保key使用的正确性,我们需要建立监控和调试机制:
// Key使用情况监控工具
class KeyMonitor {
constructor() {
this.keyUsage = new Map();
this.duplicateKeys = new Set();
this.unstableKeys = new Map();
}
// 记录key使用情况
recordKeyUsage(componentName, keys) {
const keySet = new Set(keys);
// 检查重复key
if (keySet.size !== keys.length) {
const duplicates = keys.filter((key, index) => keys.indexOf(key) !== index);
this.duplicateKeys.add(`${componentName}: ${duplicates.join(', ')}`);
console.warn(`Duplicate keys detected in ${componentName}:`, duplicates);
}
// 记录key稳定性
const previousKeys = this.keyUsage.get(componentName);
if (previousKeys) {
const unstableCount = keys.filter((key, index) =>
previousKeys[index] !== key
).length;
if (unstableCount > keys.length * 0.5) {
this.unstableKeys.set(componentName, unstableCount);
console.warn(`Unstable keys detected in ${componentName}: ${unstableCount}/${keys.length} changed`);
}
}
this.keyUsage.set(componentName, keys);
}
// 生成监控报告
generateReport() {
return {
totalComponents: this.keyUsage.size,
duplicateKeyIssues: Array.from(this.duplicateKeys),
unstableKeyComponents: Array.from(this.unstableKeys.entries()),
recommendations: this.generateRecommendations()
};
}
generateRecommendations() {
const recommendations = [];
if (this.duplicateKeys.size > 0) {
recommendations.push('修复重复key问题,确保每个key在同级组件中唯一');
}
if (this.unstableKeys.size > 0) {
recommendations.push('优化不稳定的key,使用更稳定的标识符');
}
return recommendations;
}
}
// 使用监控工具的高阶组件
function withKeyMonitoring(WrappedComponent, componentName) {
return function MonitoredComponent(props) {
const monitor = useRef(new KeyMonitor()).current;
useEffect(() => {
// 在开发环境下启用监控
if (process.env.NODE_ENV === 'development') {
const keys = extractKeysFromProps(props);
monitor.recordKeyUsage(componentName, keys);
}
});
return ;
};
}
6. 实战案例:电商商品列表优化
让我们通过一个完整的电商商品列表案例来综合应用key的最佳实践:
// 电商商品列表组件 - 完整实现
function ProductList({ products, filters, sortBy, onAddToCart, onToggleFavorite }) {
const [expandedProducts, setExpandedProducts] = useState(new Set());
const [selectedVariants, setSelectedVariants] = useState({});
// 处理商品展开/收起
const toggleProductExpansion = (productId) => {
setExpandedProducts(prev => {
const newSet = new Set(prev);
if (newSet.has(productId)) {
newSet.delete(productId);
} else {
newSet.add(productId);
}
return newSet;
});
};
// 处理变体选择
const handleVariantSelection = (productId, variantId) => {
setSelectedVariants(prev => ({
...prev,
[productId]: variantId
}));
};
// 过滤和排序商品
const processedProducts = useMemo(() => {
let filtered = products.filter(product => {
return Object.entries(filters).every(([key, value]) => {
if (!value) return true;
return product[key] === value || product[key]?.includes(value);
});
});
return filtered.sort((a, b) => {
switch (sortBy) {
case 'price_asc':
return a.price - b.price;
case 'price_desc':
return b.price - a.price;
case 'name':
return a.name.localeCompare(b.name);
case 'rating':
return b.rating - a.rating;
default:
return 0;
}
});
}, [products, filters, sortBy]);
return (
{processedProducts.map((product) => (
{product.name}
¥{product.price}
{'★'.repeat(Math.floor(product.rating))}
({product.reviewCount})
{expandedProducts.has(product.id) && (
{product.description}
{product.variants && product.variants.length > 0 && (
选择规格:
{product.variants.map((variant) => (
))}
)}
商品参数:
{Object.entries(product.specifications || {}).map(([key, value]) => (
{key}
{value}
))}
)}
))}
);
}
下面的架构图展示了这个商品列表组件的完整结构:
图4:电商商品列表架构图 - 展示了从API到UI组件的完整数据流
7. 调试工具与开发技巧
7.1 React DevTools 中的 Key 调试
React DevTools 提供了强大的key调试功能,让我们能够直观地看到组件的key使用情况:
// 开发环境下的key调试辅助工具
function KeyDebugger({ children, componentName }) {
useEffect(() => {
if (process.env.NODE_ENV === 'development') {
const keys = React.Children.map(children, child => child.key);
console.group(` Key Debug: ${componentName}`);
console.log('Keys:', keys);
console.log('Unique keys:', new Set(keys).size);
console.log('Total children:', keys.length);
if (new Set(keys).size !== keys.length) {
console.error('❌ Duplicate keys detected!');
}
if (keys.some(key => key === null)) {
console.warn('⚠️ Missing keys detected!');
}
console.groupEnd();
}
});
return <>{children};
}
// 使用示例
function DebuggableList({ items }) {
return (
{items.map(item => (
{item.name}
))}
);
}
7.2 自动化Key验证
建立自动化的key验证机制,在开发阶段就发现问题:
// ESLint 自定义规则:检查key使用
const keyValidationRule = {
meta: {
type: 'problem',
docs: {
description: 'Validate React key usage patterns',
category: 'Best Practices',
},
schema: []
},
create(context) {
return {
JSXElement(node) {
// 检查是否在数组map中使用
const parent = node.parent;
if (parent && parent.type === 'CallExpression' &&
parent.callee.property && parent.callee.property.name === 'map') {
const keyProp = node.openingElement.attributes.find(
attr => attr.name && attr.name.name === 'key'
);
if (!keyProp) {
context.report({
node,
message: 'Missing key prop in mapped element'
});
} else if (keyProp.value.type === 'JSXExpressionContainer') {
const expression = keyProp.value.expression;
// 检查是否使用数组索引
if (expression.type === 'Identifier' &&
expression.name === 'index') {
context.report({
node: keyProp,
message: 'Avoid using array index as key'
});
}
// 检查是否使用Math.random()
if (expression.type === 'CallExpression' &&
expression.callee.object &&
expression.callee.object.name === 'Math' &&
expression.callee.property.name === 'random') {
context.report({
node: keyProp,
message: 'Avoid using Math.random() as key'
});
}
}
}
}
};
}
};
8. 性能对比与测试结果
让我们通过具体的性能测试来看看不同key策略的影响:
Key策略 | 初始渲染时间 | 重排序时间 | 内存使用 | 组件复用率 |
数组索引 | 100ms | 250ms | 高 | 30% |
稳定ID | 105ms | 120ms | 中 | 85% |
组合Key | 110ms | 130ms | 中 | 80% |
随机Key | 100ms | 400ms | 极高 | 0% |
图5:不同Key策略的性能分布 - 稳定ID是最佳选择
9. 常见问题与解决方案
9.1 FAQ 快速解答
Q: 为什么不能使用数组索引作为key?
A: 当数组顺序发生变化时,索引会重新分配,导致React错误地复用组件实例,造成状态混乱。
Q: 什么时候可以使用索引作为key?
A: 只有在列表是静态的(不会重排序、插入、删除)且组件没有内部状态时才可以使用。
Q: 如何为没有唯一ID的数据生成key?
A: 可以使用内容的哈希值、组合多个字段、或在数据处理阶段添加唯一标识。
9.2 迁移指南
从错误的key使用迁移到正确实践的步骤:
// 迁移步骤1:识别问题代码
function identifyProblematicKeys(codebase) {
const issues = [];
// 扫描使用索引作为key的情况
const indexKeyPattern = /key={.*index.*}/g;
const matches = codebase.match(indexKeyPattern);
if (matches) {
issues.push({
type: 'INDEX_KEY',
count: matches.length,
severity: 'HIGH'
});
}
return issues;
}
// 迁移步骤2:重构数据结构
function addUniqueIds(dataArray) {
return dataArray.map((item, index) => ({
...item,
_id: item.id || `item_${Date.now()}_${index}`
}));
}
// 迁移步骤3:更新组件
function migrateComponent(oldComponent) {
// 将 key={index} 替换为 key={item.id}
return oldComponent.replace(
/key={.*index.*}/g,
'key={item.id || item._id}'
);
}
10. 未来发展与新特性
10.1 React 18+ 的Key优化
React 18引入了新的并发特性,对key的处理也有了优化:
// React 18 中的自动批处理与key
function ConcurrentKeyExample({ items }) {
const [selectedItems, setSelectedItems] = useState(new Set());
// 使用 startTransition 优化大列表的key更新
const handleBulkSelection = (itemIds) => {
startTransition(() => {
setSelectedItems(new Set(itemIds));
});
};
return (
{items.map(item => (
{item.name}
))}
);
}
10.2 未来的Key管理工具
展望未来,key管理可能会有更多自动化工具:
图6:Key管理工具发展历程 - 从手动到智能化的演进
总结
通过这次深入的探索,我深刻地认识到React key属性虽然看似简单,但其背后蕴含的机制却极其复杂和重要。作为一名在前端领域耕耘多年的开发者,我见证了无数因为key使用不当而引发的诡异bug,也体验过找到根本原因后的恍然大悟。
Key的本质是React用来识别和追踪组件实例的唯一标识符,它直接影响着Virtual DOM的diff算法效率和组件的生命周期管理。当我们使用数组索引作为key时,看似节省了思考成本,实际上却为应用埋下了状态混乱的定时炸弹。特别是在动态列表、条件渲染、嵌套组件等复杂场景中,错误的key使用会导致用户数据丢失、界面状态错乱、性能急剧下降等严重问题。
在实际项目中,我总结出了一套完整的key使用策略:优先使用稳定的唯一标识符,如数据库ID或UUID;在复杂嵌套结构中使用组合key确保唯一性;建立自动化的key验证机制,在开发阶段就发现潜在问题;通过性能监控工具持续优化key的使用效果。这些实践不仅能够避免bug的产生,还能显著提升应用的渲染性能和用户体验。
更重要的是,理解key的工作原理让我对React的整体架构有了更深层次的认识。从Virtual DOM的设计哲学到Fiber架构的并发特性,从组件生命周期的管理到状态更新的调度机制,key都扮演着不可或缺的角色。这种深度理解不仅帮助我写出更高质量的代码,也让我在面对复杂问题时能够快速定位根本原因,提出有效的解决方案。
随着React生态的不断发展,key的管理也在向着更加智能化的方向演进。未来我们可能会看到AI辅助的key检测工具、自动化的key生成算法、更加精准的性能优化建议。但无论工具如何进步,对基础原理的深度理解始终是我们作为开发者最宝贵的财富。只有真正掌握了key的本质,我们才能在技术的浪潮中始终保持清醒的头脑,写出既优雅又高效的代码。
我是摘星!如果这篇文章在你的技术成长路上留下了印记
️ 【关注】与我一起探索技术的无限可能,见证每一次突破
【点赞】为优质技术内容点亮明灯,传递知识的力量
【收藏】将精华内容珍藏,随时回顾技术要点
【评论】分享你的独特见解,让思维碰撞出智慧火花
️ 【投票】用你的选择为技术社区贡献一份力量
技术路漫漫,让我们携手前行,在代码的世界里摘取属于程序员的那片星辰大海!
参考链接
- React官方文档 - Lists and Keys
- React Fiber架构深度解析
- Virtual DOM与Reconciliation算法详解
- React性能优化最佳实践指南
- React DevTools使用指南与调试技巧
关键词标签
React
Key属性
Virtual DOM
状态管理
性能优化
相关文章:
React 状态丢失:组件 key 用错引发的渲染异常 - 指南
React 状态丢失:组件 key 用错引发的渲染异常 - 指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monos…...
快速实现 Excel 表格转 SVG:Java 教程 - E
如果你曾尝试过把 Excel 表格导出为 SVG 图片,就会发现 Excel 本身并不支持这种格式。虽然市面上存在一些在线转换工具,但上传文件存在效率与安全方面的顾虑。对于开发者来说,使用 Java 来实现 Excel 到 SVG 的转换,是一种更灵活、可控的方式。本文将演示如何通过简单的 Ja…...
绕过文件上传限制实现客户端路径遍历漏洞利用的技术解析
本文详细解析了如何通过精心构造JSON文件绕过PDF和图像上传验证机制,利用mmmagic、pdflib和file命令的检测特性实现客户端路径遍历攻击的技术方法与实战案例。绕过文件上传限制实现客户端路径遍历漏洞利用 在我之前的博客文章中,我演示了如何利用JSON文件作为客户端路径遍历(…...
事件总线之初步学习
第一步:创建一个eventBus.js 文件名可根据个人爱好取名即可; 内容:import Vue from vue const eventBus = new Vue(); export default eventBus;第二步:使用import EventBus from @/common/eventBus;//监听全局事件clear-login-interval EventBus.$on(clear-login-interva…...
Markdown Day04
常用DOS命令 ##查看当前目录下所有文件dir ##切换目录cd change directory ##cd..回到上一个 ##清理屏幕cls ##退出exit ##查看电脑IP,ipconfig ##打开应用 calc notepad mspaint ##ping 命令 ping www.baidu.com ##文件操作 ad 创建目录 cd> 新增文件 del 删除文件 rd 移…...
C++中类的内存存储
目录类类对象的非虚成员函数类的成员变量空类对象具有虚函数的类对象 类 类本身不会存储在内存中,类实例化的对象才会保存在内存中。但是使用 sizeof 计算类大小时能得到结果,这是因为 sizeof 会在编译时就得到类型信息,这只与类的布局有关。 类对象的非虚成员函数 考虑如下…...
PyTorch 优化器(Optimizer)
优化器(Optimizer)是深度学习训练过程中用于更新模型参数的核心组件。在训练神经网络时,我们需要通过反向传播计算损失函数相对于模型参数的梯度,然后使用优化器根据这些梯度来更新参数,以最小化损失函数。PyTorch 优化器(Optimizer)技术指南 目录优化器概念 常用优化器…...
实用指南:域名市场中,如何确认域名的价值
实用指南:域名市场中,如何确认域名的价值pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", monospace !impo…...
初步了解Neo4j
1. 是什么? Neo4j 是一个原生图数据库。它与我们熟悉的关系型数据库(如 MySQL, PostgreSQL)和 NoSQL 数据库(如 MongoDB)有根本性的不同,因为它专门为存储和查询数据之间的关系而设计。 它的核心哲学是:“关系即一等公民”。这意味着关系(或连接)和数据本身同等重要,…...
多模态和语音 AI 年度收官大会,把握 2026 技术风向标!
如果今年只参加一场多模态和语音 AI 大会,来 Convo AI & RTE2025 就够了。你是否好奇:1⃣从端到端语音模型和全双工技术,未来音频还将有哪些突破方向?2⃣如何挖掘端侧 AI 潜能,定义下一代智能硬件终端?3⃣从主动智能体到可交互世界模型,实时多模态 AI 将驱动怎样的未…...
做题
P4159 [SCOI2009] 迷路 矩阵快速幂优化递推。 首先最暴力的想法,设 $ f_{i,j} $ 在 $ j $ 时刻,到达点 $ i $ 的种类数。 枚举时间和 $ i $,然后 $ f_{i,j} = \sum\limits_{k=1}^n {f_{k,j-w[i][k]}} $。 时间很大,所以肯定行不通。 这样显然是不能用矩阵来优化的。 考虑拆…...
解码C语言函数
一、函数基本概念 1.1 函数定义 概念:把一个功能的实现流程封装起来,使用户留下接口进行调用 作用:参数创建该功能进行封装操作,返回值即通过功能显示的产出 1.2 函数组成要素返回值类型:根据函数功能而定,需要在函数头中指定子程序类的返回值类型 参数名:在函数体中提取…...
SchemaStore
Hello World本文来自博客园,作者:南宫影,转载请注明原文链接:https://www.cnblogs.com/nangongying/p/19100468...
XSS攻击防御
目录背景和价值为什么需要输出编码?不同场景下的编码方式(白话版)1. 最常见场景:内容显示在HTML标签里(比如<div>、<span>中)2. 特殊场景:内容显示在HTML标签的属性里(比如value、href中)3. 特殊场景:内容要在JavaScript代码里使用4. 特殊场景:内容作为…...
imes开发部署
一.git地址下载源码 二.后端设置 1.增加配置文件:ktg-admin/src/main/resources/application-test.yml2.临时修改代码:ktg-mes/src/main/java/com/ktg/mes/task/MesTask.java,如图注释2行。 3.快捷键Ctrl+Alt+Shift+S,打开项目结构(Project Structure)对话框4.编辑配置5…...
思维题做题记录-1
CF2600左右有趣的思维题做题记录-1 CF1458C. Latin Square 考虑将原矩阵写成 \(n\times n\) 个限制形如 \((i,j,a_{i,j})\),那么所有操作就是对这些限制进行的修改:对于 UD 操作相当于将限制改为 \((i\mp 1,j,a_{i,j})\)。 对于 LR 操作相当于将限制改为 \((i,j\mp 1,a_{i,j}…...
如何在极短时间内通透一个大型开源项目
如何在极短时间内通透一个大型开源项目前言 在现代软件开发中,快速理解和掌握大型开源项目是一项至关重要的技能。无论是参与开源贡献、技术选型,还是学习先进架构模式,都需要我们具备高效解读项目的能力。本文将以 OpenDeepWiki 项目为例,深入剖析如何运用AI技术快速通透一…...
求 Ray Ping - Gon
rt(跟风...
LCT学习笔记
LCT学习笔记从例题开始: P3690 【模板】动态树(LCT) 对于一棵静态的树,常见方法是树剖然后走链,但是在动态的情况下常见的重链或长链就会很慢,因为修改连边情况后就不满足性质了 引入一个新的方法:实链剖分,对于一个节点,任选一个儿子,连边为实边,其余为虚边,注意这…...
Visual Studio 2026 Insiders 重磅发布:AI 深度集成、性能飞跃、全新设计
近日,微软正式发布 Visual Studio 2026 Insiders!这是迄今为止 Visual StudioE 极具跨越式的一次升级。新版本不仅将 AI 深度融入开发工作流,还带来了企业级性能的显著提升,以及更轻盈、现代的界面设计,全面提升开发体验。近日,微软正式发布 Visual Studio 2026 Insiders…...
《刚刚问世》系列初窥篇-Java+Playwright自动化测试-29- 操作单选和多选按钮 - 下篇(详细教程) - 北京
1.简介 我们可能会遇到一直测试单选和复选按钮的测试场景,如果就十几道选择题,那就手工点击,马上完事,但是如果是让你测试题库呢?那不得那鼠标点击冒烟了,手指点到抽筋了。尤其是做教育类的软件测试,这些就是家常便饭了。因此今天这一篇宏哥主要是讲解一下,如何使用Pla…...
自定义注解实现服务分处理-策略模式
路由:请求标识→匹配 Service→调用 process 方法 通过自定义注解 @BusinessServiceMapping 标记具体业务 Service,注解值(如 DC 代表客户、ORD 代表订单)与请求参数中的业务标识关联;再通过 Spring 容器扫描 + 策略模式,实现 “请求标识→匹配 Service→调用 process 方…...
iOS26正式版全新风格!一文汇总实用新功能!
苹果在9月17日凌晨正式推送了iOS26系统更新,这次版本更新带来了多达61项新功能与优化。经过9个Beta版和近100天的测试,iOS26正式版终于与用户见面,版本号为23A340,更新包大小约8GB。 iOS26不仅在设计语言上焕然一新,更在AI能力、交互体验和隐私保护等多个维度进行了全面升…...
远程控制应用的中的全球节点功能如何开启?插件类型、并发数量怎么选?
不知道大家使用远程控制应用进行跨系统跨设备操作主要都是针对哪些场景呐?其实对于很多需要跨境远程办公的人群或进行售后设备升级管理的朋友来说无疑是必不可少的,甚至于海外学子们来说同样也至关重要,毕竟总有需要协助国内亲友处理问题的时刻,代操作远高于语音指导的效率…...
借助Aspose.HTML控件,使用 Python 将 HTML 转换为 DOCX
Aspose.HTML for Python via .NET提供了用于自动执行文件格式转换任务的类和方法。此外,它能够精确地转换 HTML 结构和样式,是 Python 开发人员的理想选择。本教程将向开发者展示如何在 Python 中以编程方式将HTML转换为DOCX。我们将使用一个非常快速的 Python SDK 将网页转换…...
openEuler 24.03 (LTS-SP2)安装mysql 8.0.41
环境:OS:openEuler 24.03 (LTS-SP2)(安装时候没有图形界面的选择项可选)mysql:8.0.41 glib.2.17 操作系统下载https://www.openeuler.org/en/download/#openEuler%2024.03%20LTS%20SP2查看系统glibc版本[root@localhost soft]# ldd --versionldd (GNU libc) 2.38Copyright (C) …...
7.数据库归档异常检查与处理
备库: select instance_name,status from v$instance; select open_mode from v$database; @dgstat 如果都是00:00:00则说明本地从生产到DR同步没有问题 @dgpro 与上面的RFS的sequence#进行对比,可以算出生产与DR相差的sequence Block# 1分钟前是852100,1分钟后是856100,…...
Gitlab 关键字
核心原则:一切路径始于项目根目录:https://blog.csdn.net/qq_14829643/article/details/150773286include: local:中的所有路径都是相对于当前项目的根目录进行解析的。它既不是传统意义上的“绝对路径”(如 /etc/gitlab-runner/config.toml,这会指向 Runner 服务器的文件…...
8.listener日志占用过大处理方法
ps -ef |grep tns asmenv 查询listener.log的位置路径 lsnrctl status [listener name] 例如: listener log file : /oracle/TEST/diag/tnslsnr/xianigux/listener/alert/log.xml cd /oracle/TEST/diag/tnslsnr/xianigux/listener/alert 删除除了log.xml以外的所有xml文件 rm …...
马建仓AI助手完成全链路升级:三十余项新能力重塑研发工作流
马建仓AI助手完成全链路升级:三十余项新能力重塑研发工作流 在数字化转型浪潮席卷各行各业的当下,研发效率正成为企业竞争力的关键指标。马建仓AI助手近日宣布完成面向真实研发流程的全面升级,新增三十余项智能能力,覆盖需求、开发、测试、项目管理等关键环节,标志着企业级…...
线性回归与 Softmax 回归:深度学习基础模型解析 - 实践
线性回归与 Softmax 回归:深度学习基础模型解析 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", mon…...
浏览器下载,一定要开启这个隐藏功能!
大家好,我是 Immerse,一名独立开发者、内容创作者。关注公众号:沉浸式趣谈,获取最新文章(更多内容只在公众号更新) 个人网站:https://yaolifeng.com 也同步更新。 转载请在文章开头注明出处和版权信息。我会在这里分享关于编程、独立开发、AI干货、开源、个人思考等内容…...
开源项目进度管理系统 PJMan:让技术项目进度可视化、数据化的利器
在软件项目管理过程中,进度不透明、任务卡点难定位、人员效率难量化是许多技术团队面临的痛点。今天为大家介绍一款开源项目进度管理系统 ——PJMan,其「项目概览」页面通过分层可视化与数据驱动的设计,将项目的 “全局趋势、任务细节、人员效率” 全方位呈现,为技术团队提…...
【光照】[漫反射]UnityURP兰伯特能量守恒吗?
【从UnityURP开始探索游戏渲染】专栏-直达兰伯特漫反射的能量守恒性 能量守恒基本原理 在物理正确的渲染中,能量守恒要求:表面反射的光能总量 ≤ 入射光能 漫反射+高光反射 ≤ 1.0 没有能量凭空产生或消失经典兰伯特模型的能量守恒问题 传统兰伯特漫反射公式: $漫反…...
Microsoft AI Genius 限时挑战赛:实战开启,等你应战!
通过 Microsoft AI Genius 系列 2.0 的实战专题课程,相信各位开发者对智能 GitHub Copilot 副驾驶 Agent Mode、Azure AI Foundry Agent Service(国际版)及 Copilot Studio 的理解与掌握达到了新高度。现在,是时候将所学理论转化为实际行动,投身真实场景检验成果了。 ↓↓…...
DevSecOps革命:测试工具如何重塑企业数字化转型的质量防线
DevSecOps革命:测试工具如何重塑企业数字化转型的质量防线 在数字化转型浪潮席卷全球的当下,软件质量保障体系正经历着前所未有的范式转变。DevSecOps作为这场变革的核心方法论,正在重新定义测试工具在企业技术栈中的战略地位。从单纯的"质量守门员"到贯穿全生命周…...
3.sysaux tablesace 清理
select min(snap_id),max(snap_id) from dba_hist_snapshot; 查完后,记录min和max的值 select dbid from v$database; 18701与18953分别为min与max的snap_id的值,387090299为dbid的值,将这些值代入下面的语句执行 begin dbms_workload_repository.drop_snapshot_range( low_…...
2.LOCK session
select * from v$session_blockers; 或者 select * from gv$session_blockers; (在rac情况下) 通过 select count(1) from v$locked_object; 可以查出内容 首先询问客户能否提供lock table的session sid和serial#,如果客户只能提供session sid,则 可以使用: select sid,ser…...
2025 ~ 2026 游击 - gfoi
2025/09/19 试了试 CSP-S 的历年题目,2019 年有 84.5 分。...
【初赛】第二类斯特林数意义 - Slayer
第二类斯特林数(斯特林子集数) \(\begin{Bmatrix}n\\ k\end{Bmatrix}\),也可记做 \(S(n,k)\),表示将 \(n\) 个两两不同的元素,划分为 \(k\) 个互不区分的非空子集的方案数。 通项公式 \(\begin{Bmatrix}n\\m\end{Bmatrix}=\sum\limits_{i=0}^m\dfrac{(-1)^{m-i}i^n}{i!(m-…...
在AI技术快速实现功能的时代,挖掘新需求成为核心竞争力——某知名Android面试题库需求洞察
该篇文章无摘要a.内容描述 该项目是一个专注于Android开发领域的技术面试题库,核心功能定位为提供全面的Android面试问题与答案集合,帮助开发者准备技术面试。关键应用场景包括Android开发者求职准备、技术知识查漏补缺、面试官题库参考等。项目内容覆盖了Android开发的各个方…...
php本地搭建知识库实现rag遇到的一些问题解决方式
1、向量化的问题,中文的话,使用尽量使用国内的嵌入模型,国外的虽然支持中文,但是还是比不上国内专门针对中文的优化 本地使用ollama 搭建的话 ,我使用的是 quentinz/bge-large-zh-v1.5:latest2、不规则的pdf文件,无法使用pdf插件读取内容问题,我是php 使用 smalot/pdf…...
docker操作包括使用docker制作为接口
Docker 化 Flask OCR 应用指南 1. 创建必要的文件 在你的 Flask 应用项目根目录下,你需要创建以下文件: 1.1 Dockerfile 这是一个文本文件,包含了构建 Docker 镜像所需的所有指令1 # 使用官方 Python 3.10 (Python 3.13)精简版作为基础镜像,减小镜像体积2 FROM python:3.…...
BuildingSystemPlugin使用指南
使用自定义碰撞 1.启用Use Custom Overlay:2.修改Overlapping Box的BoxExtent来设置大小(不能设置Scale来设置大小):...
openEuler 24.03 (LTS-SP2)安装mysql5.7.42
环境:OS:openEuler 24.03 (LTS-SP2)(安装时候没有图形界面的选择项可选)mysql:5.7.42 glib.2.17 操作系统下载https://www.openeuler.org/en/download/#openEuler%2024.03%20LTS%20SP2 查看系统glibc版本[root@localhost soft]# ldd --versionldd (GNU libc) 2.38Copyright (C)…...
Trae AI IDE与Gitee MCP深度整合:开启智能协作开发新时代
Trae AI IDE与Gitee MCP深度整合:开启智能协作开发新时代 在AI技术快速渗透软件开发领域的当下,字节跳动推出的Trae AI IDE凭借其创新的智能编码能力,正在重塑开发者的工作流程。这款国产AI编程工具通过深度整合Gitee MCP(Multi-agent Collaboration Platform)服务,为开发…...
LangChain 入门:从 0 到 1 搞懂 LLM 应用开发框架
LangChain 入门:从 0 到 1 搞懂 LLM 应用开发框架如果你常逛技术社区,大概率听过 “大语言模型(LLM)能做很多事”—— 写文案、答问题、编代码,但真要把它放进实际业务里,比如给公司做个智能客服、给团队搭个文档问答工具,却总卡壳:要么模型记不住上下文,聊两句就 “…...
[JOI Open 2023] 古代机器 2 / Ancient Machine 2 题解
[JOI Open 2023] 古代机器 2 / Ancient Machine 2传送门:[JOI Open 2023] 古代机器 2 / Ancient Machine 2 完全不会做这种交互题。 形式化题意:交互库有一个 01 串 \(s\)(下标从 \(0\) 开始),你需要通过若干次询问求出 \(s\),每次询问,你可以构造一个大小为 \(m\) 的自…...
Visual Studio 2022配置fftw第三方库
#visual studio#ide 目录1. 介绍 2.获取FFTW 3.生成lib文件 4.在VS2022中的项目属性中进行配置 5.测试代码 参考链接 1. 介绍 FFTW是一个可以进行可变长度一维或多维DFT的开源C程序库,是目前最快的FFT算法实现。本文简述了在Windows平台上,如何在C++中调用FFTW,所使用的IDE…...
[React] nextjs useSWR导致的死循环,一直重复渲染rerender
export const useDashboards = () => {// return useSWR<Dashboard[]>("/api/dashboards");return JSON.parse("[xxxxxxxxxx]")}使用一段mockup的data, 导致useEffect(()=>{doSth}, Dashboards)里面的Dashboards一直变化, 在一堆代码里找了几…...