当前位置: 首页 > news >正文

React Hooks 深入浅出

目录

  1. 引言:React Hooks 的革命
  2. 基础 Hooks
    • useState:状态管理的新方式
    • useEffect:组件生命周期的替代方案
    • useContext:简化 Context API
  3. 额外的 Hooks
    • useReducer:复杂状态逻辑的管理
    • useCallback 与 useMemo:性能优化利器
    • useRef:引用 DOM 和保存变量
  4. 自定义 Hooks:逻辑复用的最佳实践
  5. Hooks 使用规则与陷阱
  6. 实战案例:使用 Hooks 重构传统组件
  7. 总结与展望

引言:React Hooks 的革命

React Hooks 是 React 16.8 版本中引入的特性,它彻底改变了 React 组件的编写方式。在 Hooks 出现之前,我们需要使用类组件来管理状态和生命周期,而函数组件则被视为"无状态组件"。Hooks 的出现使得函数组件也能够拥有状态和生命周期功能,从而简化了组件逻辑,提高了代码的可读性和可维护性。

Hooks 解决了 React 中的一些长期存在的问题:

  • 组件之间难以复用状态逻辑:在 Hooks 之前,我们通常使用高阶组件(HOC)或 render props 模式来复用组件逻辑,但这些方法往往导致组件嵌套过深,形成"嵌套地狱"。
  • 复杂组件变得难以理解:生命周期方法中常常混杂着不相关的逻辑,而相关逻辑却分散在不同的生命周期方法中。
  • 类组件的困惑:类组件需要理解 JavaScript 中 this 的工作方式,这对新手不太友好。

接下来,我们将深入探讨 React Hooks 的各个方面,从基础用法到高级技巧,帮助你全面掌握这一强大特性。

基础 Hooks

useState:状态管理的新方式

useState 是最基础也是最常用的 Hook,它让函数组件能够拥有自己的状态。

import React, { useState } from 'react';function Counter() {// 声明一个叫 "count" 的 state 变量,初始值为 0const [count, setCount] = useState(0);return (<div><p>你点击了 {count} 次</p><button onClick={() => setCount(count + 1)}>点击我</button></div>);
}

useState 返回一个数组,包含两个元素:当前状态值和一个更新该状态的函数。我们使用数组解构来获取这两个值。

useState 的高级用法

  1. 函数式更新:当新的状态依赖于之前的状态时,推荐使用函数式更新。
// 不推荐
setCount(count + 1);// 推荐
setCount(prevCount => prevCount + 1);
  1. 惰性初始化:如果初始状态需要通过复杂计算获得,可以传递一个函数给 useState
const [state, setState] = useState(() => {const initialState = someExpensiveComputation(props);return initialState;
});

useEffect:组件生命周期的替代方案

useEffect 让你在函数组件中执行副作用操作,如数据获取、订阅或手动更改 DOM 等。它统一了 componentDidMountcomponentDidUpdatecomponentWillUnmount 这三个生命周期方法。

import React, { useState, useEffect } from 'react';function Example() {const [count, setCount] = useState(0);// 类似于 componentDidMount 和 componentDidUpdateuseEffect(() => {// 更新文档标题document.title = `你点击了 ${count} 次`;// 返回一个清理函数,类似于 componentWillUnmountreturn () => {document.title = 'React App';};}, [count]); // 仅在 count 更改时更新return (<div><p>你点击了 {count} 次</p><button onClick={() => setCount(count + 1)}>点击我</button></div>);
}

useEffect 的依赖数组

  • 空数组 []:效果只在组件挂载和卸载时执行一次,类似于 componentDidMountcomponentWillUnmount
  • 有依赖项 [a, b]:效果在组件挂载时以及依赖项变化时执行。
  • 无依赖数组:效果在每次渲染后执行。

useContext:简化 Context API

useContext 让你可以订阅 React 的 Context,而不必使用 Context.Consumer 组件。

import React, { useContext } from 'react';// 创建一个 Context
const ThemeContext = React.createContext('light');function ThemedButton() {// 使用 useContext 获取当前主题const theme = useContext(ThemeContext);return (<button style={{ background: theme === 'dark' ? '#333' : '#fff', color: theme === 'dark' ? '#fff' : '#333' }}>我是一个主题按钮</button>);
}function App() {return (<ThemeContext.Provider value="dark"><ThemedButton /></ThemeContext.Provider>);
}

useContext 接收一个 Context 对象(由 React.createContext 创建)并返回该 Context 的当前值。当 Provider 更新时,使用该 Context 的组件会重新渲染。

额外的 Hooks

useReducer:复杂状态逻辑的管理

useReduceruseState 的替代方案,适用于有复杂状态逻辑的场景,特别是当下一个状态依赖于之前的状态时。

import React, { useReducer } from 'react';// 定义 reducer 函数
function reducer(state, action) {switch (action.type) {case 'increment':return { count: state.count + 1 };case 'decrement':return { count: state.count - 1 };default:throw new Error();}
}function Counter() {// 使用 useReducerconst [state, dispatch] = useReducer(reducer, { count: 0 });return (<div>Count: {state.count}<button onClick={() => dispatch({ type: 'increment' })}>+</button><button onClick={() => dispatch({ type: 'decrement' })}>-</button></div>);
}

useReducer 返回当前状态和 dispatch 函数。dispatch 函数用于触发状态更新,它接收一个 action 对象,通常包含 type 属性和可选的 payload。

useCallback 与 useMemo:性能优化利器

这两个 Hooks 主要用于性能优化,避免不必要的计算和渲染。

useCallback:返回一个记忆化的回调函数,只有当依赖项变化时才会更新。

import React, { useState, useCallback } from 'react';function ParentComponent() {const [count, setCount] = useState(0);// 使用 useCallback 记忆化回调函数const handleClick = useCallback(() => {console.log(`Button clicked, count: ${count}`);}, [count]); // 只有当 count 变化时,handleClick 才会更新return (<div><ChildComponent onClick={handleClick} /><button onClick={() => setCount(count + 1)}>Increment</button></div>);
}// 使用 React.memo 优化子组件
const ChildComponent = React.memo(({ onClick }) => {console.log('ChildComponent rendered');return <button onClick={onClick}>Click me</button>;
});

useMemo:返回一个记忆化的值,只有当依赖项变化时才重新计算。

import React, { useState, useMemo } from 'react';function ExpensiveCalculation({ a, b }) {// 使用 useMemo 记忆化计算结果const result = useMemo(() => {console.log('Computing result...');// 假设这是一个耗时的计算return a * b;}, [a, b]); // 只有当 a 或 b 变化时,才重新计算return <div>Result: {result}</div>;
}

useRef:引用 DOM 和保存变量

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数。返回的 ref 对象在组件的整个生命周期内保持不变。

引用 DOM 元素

import React, { useRef, useEffect } from 'react';function TextInputWithFocusButton() {// 创建一个 refconst inputRef = useRef(null);// 点击按钮时聚焦输入框const focusInput = () => {inputRef.current.focus();};return (<div><input ref={inputRef} type="text" /><button onClick={focusInput}>聚焦输入框</button></div>);
}

保存变量

import React, { useState, useRef, useEffect } from 'react';function Timer() {const [count, setCount] = useState(0);// 使用 useRef 保存 interval IDconst intervalRef = useRef(null);useEffect(() => {// 设置定时器intervalRef.current = setInterval(() => {setCount(c => c + 1);}, 1000);// 清理定时器return () => {clearInterval(intervalRef.current);};}, []); // 空依赖数组,只在挂载和卸载时执行// 停止计时器const stopTimer = () => {clearInterval(intervalRef.current);};return (<div><p>计数: {count}</p><button onClick={stopTimer}>停止</button></div>);
}

useState 不同,useRef.current 属性变化不会触发组件重新渲染。

自定义 Hooks:逻辑复用的最佳实践

自定义 Hooks 是 React Hooks 最强大的特性之一,它允许你将组件逻辑提取到可重用的函数中。自定义 Hook 是一个以 “use” 开头的 JavaScript 函数,可以调用其他 Hooks。

示例:创建一个 useLocalStorage Hook

import { useState, useEffect } from 'react';// 自定义 Hook:使用 localStorage 持久化状态
function useLocalStorage(key, initialValue) {// 初始化状态const [storedValue, setStoredValue] = useState(() => {try {// 尝试从 localStorage 获取值const item = window.localStorage.getItem(key);// 如果存在则解析并返回,否则返回初始值return item ? JSON.parse(item) : initialValue;} catch (error) {console.log(error);return initialValue;}});// 更新 localStorage 的函数const setValue = value => {try {// 允许值是一个函数,类似于 useStateconst valueToStore = value instanceof Function ? value(storedValue) : value;// 保存到 statesetStoredValue(valueToStore);// 保存到 localStoragewindow.localStorage.setItem(key, JSON.stringify(valueToStore));} catch (error) {console.log(error);}};return [storedValue, setValue];
}// 使用自定义 Hook
function App() {const [name, setName] = useLocalStorage('name', 'Bob');return (<div><inputtype="text"value={name}onChange={e => setName(e.target.value)}/></div>);
}

示例:创建一个 useWindowSize Hook

import { useState, useEffect } from 'react';// 自定义 Hook:获取窗口尺寸
function useWindowSize() {// 初始化状态const [windowSize, setWindowSize] = useState({width: undefined,height: undefined,});useEffect(() => {// 处理窗口大小变化的函数function handleResize() {setWindowSize({width: window.innerWidth,height: window.innerHeight,});}// 添加事件监听器window.addEventListener('resize', handleResize);// 初始调用一次以设置初始值handleResize();// 清理函数return () => window.removeEventListener('resize', handleResize);}, []); // 空依赖数组,只在挂载和卸载时执行return windowSize;
}// 使用自定义 Hook
function ResponsiveComponent() {const size = useWindowSize();return (<div>{size.width < 768 ? (<p>在小屏幕上显示</p>) : (<p>在大屏幕上显示</p>)}</div>);
}

Hooks 使用规则与陷阱

使用 Hooks 时,必须遵循两条重要规则:

  1. 只在最顶层使用 Hooks:不要在循环、条件或嵌套函数中调用 Hooks,确保 Hooks 在每次组件渲染时都以相同的顺序被调用。
// ❌ 错误:在条件语句中使用 Hook
function Form() {const [name, setName] = useState('Mary');if (name !== '') {useEffect(() => {localStorage.setItem('name', name);});}// ...
}// ✅ 正确:将条件放在 Hook 内部
function Form() {const [name, setName] = useState('Mary');useEffect(() => {if (name !== '') {localStorage.setItem('name', name);}});// ...
}
  1. 只在 React 函数组件或自定义 Hooks 中调用 Hooks:不要在普通的 JavaScript 函数中调用 Hooks。

常见陷阱与解决方案

  1. 依赖数组遗漏
// ❌ 错误:依赖数组遗漏了 count
function Counter({ count }) {useEffect(() => {document.title = `Count: ${count}`;}, []); // 依赖数组为空,但使用了 count// ...
}// ✅ 正确:添加所有依赖项
function Counter({ count }) {useEffect(() => {document.title = `Count: ${count}`;}, [count]); // 正确添加了 count 作为依赖项// ...
}
  1. 闭包陷阱
// ❌ 问题:使用过时的状态值
function Counter() {const [count, setCount] = useState(0);useEffect(() => {const timer = setInterval(() => {console.log(`Current count: ${count}`);setCount(count + 1); // 这里的 count 是闭包捕获的初始值}, 1000);return () => clearInterval(timer);}, []); // 依赖数组为空,导致 count 始终为初始值 0// ...
}// ✅ 解决方案:使用函数式更新
function Counter() {const [count, setCount] = useState(0);useEffect(() => {const timer = setInterval(() => {setCount(prevCount => prevCount + 1); // 使用函数式更新获取最新状态}, 1000);return () => clearInterval(timer);}, []); // 现在可以安全地使用空依赖数组// ...
}
  1. 过度依赖 useEffect
// ❌ 不必要的 useEffect
function Form() {const [firstName, setFirstName] = useState('');const [lastName, setLastName] = useState('');// 不必要的 useEffect,可以直接计算const [fullName, setFullName] = useState('');useEffect(() => {setFullName(`${firstName} ${lastName}`);}, [firstName, lastName]);// ...
}// ✅ 更好的方式:直接计算派生状态
function Form() {const [firstName, setFirstName] = useState('');const [lastName, setLastName] = useState('');// 直接计算派生值,无需额外的状态和 useEffectconst fullName = `${firstName} ${lastName}`;// ...
}

实战案例:使用 Hooks 重构传统组件

让我们通过一个实际例子,展示如何将类组件重构为使用 Hooks 的函数组件。

原始类组件

import React, { Component } from 'react';class UserProfile extends Component {constructor(props) {super(props);this.state = {user: null,loading: true,error: null};}componentDidMount() {this.fetchUserData();}componentDidUpdate(prevProps) {if (prevProps.userId !== this.props.userId) {this.fetchUserData();}}fetchUserData = async () => {this.setState({ loading: true });try {const response = await fetch(`https://api.example.com/users/${this.props.userId}`);const data = await response.json();this.setState({ user: data, loading: false });} catch (error) {this.setState({ error, loading: false });}};render() {const { user, loading, error } = this.state;if (loading) return <div>Loading...</div>;if (error) return <div>Error: {error.message}</div>;if (!user) return <div>No user data</div>;return (<div><h1>{user.name}</h1><p>Email: {user.email}</p><p>Phone: {user.phone}</p></div>);}
}

使用 Hooks 重构后的函数组件

import React, { useState, useEffect } from 'react';function UserProfile({ userId }) {const [user, setUser] = useState(null);const [loading, setLoading] = useState(true);const [error, setError] = useState(null);useEffect(() => {async function fetchUserData() {setLoading(true);try {const response = await fetch(`https://api.example.com/users/${userId}`);const data = await response.json();setUser(data);setLoading(false);} catch (error) {setError(error);setLoading(false);}}fetchUserData();}, [userId]); // 依赖项数组,只有当 userId 变化时才重新获取数据if (loading) return <div>Loading...</div>;if (error) return <div>Error: {error.message}</div>;if (!user) return <div>No user data</div>;return (<div><h1>{user.name}</h1><p>Email: {user.email}</p><p>Phone: {user.phone}</p></div>);
}

进一步优化:提取自定义 Hook

import React, { useState, useEffect } from 'react';// 自定义 Hook:获取用户数据
function useUserData(userId) {const [user, setUser] = useState(null);const [loading, setLoading] = useState(true);const [error, setError] = useState(null);useEffect(() => {async function fetchUserData() {setLoading(true);try {const response = await fetch(`https://api.example.com/users/${userId}`);const data = await response.json();setUser(data);setLoading(false);} catch (error) {setError(error);setLoading(false);}}fetchUserData();}, [userId]);return { user, loading, error };
}// 使用自定义 Hook 的组件
function UserProfile({ userId }) {const { user, loading, error } = useUserData(userId);if (loading) return <div>Loading...</div>;if (error) return <div>Error: {error.message}</div>;if (!user) return <div>No user data</div>;return (<div><h1>{user.name}</h1><p>Email: {user.email}</p><p>Phone: {user.phone}</p></div>);
}

通过这个例子,我们可以看到 Hooks 带来的几个明显优势:

  1. 代码更简洁:函数组件比类组件代码量少,更易于阅读和理解。
  2. 关注点分离:通过自定义 Hook,我们可以将数据获取逻辑与 UI 渲染逻辑分离。
  3. 逻辑复用:自定义 Hook 可以在多个组件之间复用,而不需要使用 HOC 或 render props。

总结与展望

React Hooks 彻底改变了 React 组件的编写方式,使函数组件成为了 React 开发的主流。通过本文,我们深入探讨了 React Hooks 的基础知识、高级用法、常见陷阱以及最佳实践。

Hooks 的优势总结:

  1. 简化组件逻辑:使用 Hooks,我们可以将相关的逻辑放在一起,而不是分散在不同的生命周期方法中。
  2. 促进逻辑复用:自定义 Hooks 提供了一种比 HOC 和 render props 更简洁的逻辑复用方式。
  3. 更好的类型推断:在 TypeScript 中,Hooks 比类组件有更好的类型推断。
  4. 减少代码量:函数组件通常比等效的类组件代码量少。
  5. 更容易测试:纯函数更容易测试,Hooks 使得编写纯函数组件变得更加容易。

随着 React 的发展,Hooks 生态系统也在不断壮大。React 团队还在探索更多的 Hooks,如 useTransitionuseDeferredValue,以解决并发模式下的性能问题。同时,社区也开发了大量的第三方 Hooks 库,如 react-useuse-http 等,进一步扩展了 Hooks 的能力。


参考资料:

  1. React 官方文档 - Hooks 介绍
  2. React Hooks 完全指南
  3. 使用 React Hooks 的常见错误
  4. 深入理解 React useEffect

相关文章:

React Hooks 深入浅出

目录 引言&#xff1a;React Hooks 的革命基础 Hooks useState&#xff1a;状态管理的新方式useEffect&#xff1a;组件生命周期的替代方案useContext&#xff1a;简化 Context API 额外的 Hooks useReducer&#xff1a;复杂状态逻辑的管理useCallback 与 useMemo&#xff1a;…...

解释 NestJS 的架构理念(例如,模块化、可扩展性、渐进式框架)

一、模块化设计 // user.module.ts Module({controllers: [UserController], // 当前模块的控制器providers: [UserService], // 当前模块的服务exports: [UserService] // 暴露给其他模块使用的服务 }) export class UserModule {}// order.module.ts Module({…...

Caffeine快速入门

依赖 <dependency><groupId>com.github.ben-manes.caffeine</groupId><artifactId>caffeine</artifactId><version>3.2.0</version> </dependency> Cache的基本api操作 Caffeine.newBuilder.build来构建Caffeine .maximumS…...

【踩坑记录】项目Bug分析:一次因 `String.isBlank()` 引发的崩溃(No such instance method: ‘isBlank‘)

项目Bug分析&#xff1a;一次因 String.isBlank() 引发的崩溃 一、前言 在日常的 Java 项目开发中&#xff0c;使用 String 的常见工具方法如 isEmpty()、trim() 等已司空见惯。然而&#xff0c;近期在一次项目中使用了 String.isBlank() 方法&#xff0c;结果竟然直接导致崩…...

SpringBoot整合Kafka、Flink实现流式处理

引言 在当今大数据处理领域&#xff0c;实时数据流处理变得越来越重要。Apache Kafka作为一个高吞吐量的分布式流处理平台&#xff0c;结合Apache Flink这一强大的流处理框架&#xff0c;可以构建出高效的实时数据处理系统。本文将指导您如何在SpringBoot应用中整合Kafka和Fli…...

互联网大厂Java求职面试:云原生与AI融合下的系统设计挑战-2

互联网大厂Java求职面试&#xff1a;云原生与AI融合下的系统设计挑战-2 第一轮提问&#xff1a;云原生架构选型与微服务治理 面试官&#xff08;技术总监&#xff09;&#xff1a;郑薪苦&#xff0c;我们先从一个基础问题开始。你了解Spring Cloud和Kubernetes在微服务架构中…...

AI算力产业领域产品全景图:从硬件基础到应用场景

目录 1、硬件产品 2、 软件产品 3、云服务产品 4、边缘计算产品 5、AI应用产品 6、AI安全产品 7、AI合规产品 8、AI教培产品 9、AI研创产品 10、AI生态产品 在人工智能迅猛发展的今天,算力已成为推动AI技术进步与应用落地的核心驱动力。随着深度学习模型规模的不断膨…...

【优选算法 | 模拟】探索模拟算法: 编程与问题分析的双重 考验

算法相关知识点可以通过点击以下链接进行学习一起加油&#xff01;双指针滑动窗口二分查找前缀和位运算 在本篇文章中&#xff0c;我们将深入解析模拟算法的原理。从基础概念到实际应用&#xff0c;带你了解如何通过模拟算法高效解决各种问题。无论你是刚接触算法的新手&#x…...

根据蓝牙名称自动匹配对应 UI

要实现“根据蓝牙名称自动匹配对应 UI”&#xff0c;并且支持未来不断增加的按摩椅型号和UI&#xff0c;推荐采用插件式UI注册自动路由的架构。下面是详细的可执行方案&#xff0c;适合你当前的 Flutter 项目结构&#xff1a; 1. 目录结构设计 假设每个按摩椅型号有独立的UI页…...

【25软考网工】第五章(7)路由协议、静态与默认路由、路由协议分类

目录 一、路由协议 1. 路由 2. 路由器工作原理 3. 查看路由表 4. IP路由查找的最长匹配原则 1&#xff09;例题#最长匹配原则示例题 5. 应用案例 1&#xff09;例题#路由优先级判断 2&#xff09;例题#路由信息内容 3&#xff09;例题#路由表迭代与静态路由 4&#…...

Rice Science∣武汉大学水稻研究团队发现水稻壁相关激酶OsWAKg16和OsWAKg52同时调控水稻抗病性和产量

近日&#xff0c;农学领域国际期刊Rice Science在线发表了武汉大学杂交水稻全国重点实验室范峰峰博士题为“Identification and Characterization of WAKg Genes Involved in Rice Disease Resistance and Yield”的研究论文。该论文系统分析了水稻壁相关激酶中包含半乳糖醛酸结…...

Spark,所用几个网页地址

hadoop的三大组成&#xff1a; 1. HDFS&#xff1a;存储。文件上传&#xff0c;下载 2. MapReduce&#xff1a;计算。词频统计&#xff0c;流量统计 3. YARN&#xff1a;调度 History Server网址&#xff1a;192.168.56.100:18080HDFS的NameNode网址&#xff1a;http://hadoop1…...

K8S PV 与 PVC 快速开始、入门实战

假设有如下三个节点的 K8S 集群&#xff1a; ​ k8s31master 是控制节点 k8s31node1、k8s31node2 是工作节点 容器运行时是 containerd 一、什么是 PV 与 PVC 1.1、什么是 PV&#xff08;PersistentVolume 持久卷&#xff09; PV 是集群中由管理员配置的一段网络存储&#xf…...

5月6(信息差)

一、经济与贸易 中美关税谈判进展 美方近期多次主动向中方传递谈判信号,中方回应称“谈的大门始终敞开”,但强调美方需先取消单边加征关税等错误做法78。 美国第一季度GDP环比下降0.3%,为2022年第二季度以来新低,经济压力或推动其加快谈判进程78。 全球贸易政策变动 特朗普…...

购物|电商购物小程序|基于微信小程序的购物系统设计与实现(源码+数据库+文档)

电商购物小程序 目录 基于微信小程序的购物系统设计与实现 一、前言 二、系统功能设计 三、系统实现 1、用户前台功能实现 2、管理员后台功能实现 四、数据库设计 1、实体ER图 2、具体的表设计如下所示&#xff1a; 五、核心代码 六、论文参考 七、最新计算机毕设选题…...

基于k8s的Jenkins CI/CD平台部署实践(三):集成ArgoCD实现持续部署

基于k8s的Jenkins CI/CD平台部署实践&#xff08;三&#xff09;&#xff1a;集成ArgoCD实现持续部署 文章目录 基于k8s的Jenkins CI/CD平台部署实践&#xff08;三&#xff09;&#xff1a;集成ArgoCD实现持续部署一、Argocd简介二、安装Helm三、Helm安装ArgoCD实战1. 添加Arg…...

Python实例题:高德API+Python解决租房问题

目录 Python实例题 题目 python-amap-rental结合高德 API 和 Python 解决租房问题的脚本 代码解释 get_geocode 函数&#xff1a; search_rentals 函数&#xff1a; 主程序&#xff1a; 运行思路 注意事项 Python实例题 题目 高德APIPython解决租房问题 python-ama…...

WIN10 系统增加MYSQL环境变量示例

说明&#xff1a; 由于安装MYSQL需要添加到环境变量后才能启动运行&#xff0c;这里记录一下添加mysql环境变量的过程。 1、进入我的电脑-属性 2、找到高级设置 3、找到环境变量 4、找到PATH 5、双击进入后通过新建添加对应MYSQL的安装路径&#xff08;.exe所在的bin路径&…...

NetApp SAS 连接线:铜缆与光缆的全面介绍

写在前面 NetApp 的磁盘扩展柜&#xff0c;主要是12GB的shelf&#xff0c;如DS212C,224C,460C等&#xff0c;这些shelf中间的互联或者控制器到shelf的连接都是通过12Gb的SAS线来连接的&#xff0c;以实现高速数据传输。SAS 连接线是这一过程中的核心组件。但是NetApp的SAS连接…...

CSS中的@import指令

一、什么是import指令&#xff1f; import 是CSS提供的一种引入外部样式表的方式&#xff0c;允许开发者在CSS文件中引入其他CSS文件&#xff0c;或者在HTML的<style>标签中引入外部样式。与常见的<link>标签相比&#xff0c;import 提供了一种更“CSS原生”的样式…...

tinyrenderer笔记(上)

tinyrenderer个人代码仓库&#xff1a;tinyrenderer个人练习代码参考笔记&#xff1a;从零构建光栅器&#xff0c;tinyrenderer笔记&#xff08;上&#xff09; - 知乎 第 1 课&#xff1a;Bresenham 画线算法 Bresenham 画线算法&#xff1a;Bresenham 直线算法 - 知乎 第一…...

VS2022 Qt配置Qxlsx

目录 1、下载QXlsx&#xff0c;并解压文件夹 ​编辑2、打开VS2022配置QXlsx 3、VS配置Qxslx库 方法一&#xff1a;常规方法 方法二&#xff1a;直接使用源码 方法三&#xff1a;将QXlsx添加到Qt安装目录&#xff08;暂时尝试未成功&#xff09; 1、下载QXlsx&#xff0c;…...

C++ 渗透 数据结构中的二叉搜索树

欢迎来到干货小仓库 "沙漠尽头必是绿洲。" --面对技术难题时&#xff0c;坚持终会看到希望。 1.二叉搜索树的概念 二叉搜索树又称二叉排序树&#xff0c;它或者是一颗空树&#xff0c;或者是具有以下性质的二叉树&#xff1a; a、若它的左子树不为空&#xff0c;则…...

JavaScript学习教程,从入门到精通,jQuery 单击页面显示自定义动画、元素删除操作、随机抽奖、随机选图并放大语法知识点(37)

jQuery 单击页面显示自定义动画、元素删除操作、随机抽奖、随机选图并放大语法知识点 1. jQuery 基础语法 1.1 引入 jQuery 在使用 jQuery 之前&#xff0c;需要先引入 jQuery 库。可以通过 CDN 引入&#xff0c;也可以下载到本地使用。 <!-- 通过 CDN 引入 jQuery -->…...

5.6 react组件化开发基础

react 组件开发基础 组件分类与组件使用 组件传参 父传子 【函数数据传值 实参 形参对应关系】 子传父 插槽 透传 useContext 上下文&#xff08;作用域&#xff09; 跨层级调用方法 通过子组件的实例对象useRef 直接调用子组件的方法 和数据 状态管理&#xff08;非常多…...

react-14defaultValue(仅在首次渲染时生效)和value(受 React 状态控制)

在 React 中&#xff0c;defaultChecked/checked 和 defaultValue/value 是用于处理表单元素初始值和受控值的属性对。区别在于表单元素是否受 React 组件状态控制。 1. defaultValue 作用&#xff1a;设置表单元素的初始值&#xff08;仅在首次渲染时生效&#xff09;。特点…...

HarmonyOS 5.0 低时延音视频开发​​

大家好&#xff0c;我是 V 哥。 在HarmonyOS 5.0的开发中&#xff0c;支持低时延音视频开发&#xff0c;为了确保语法正确&#xff0c; V 哥以下代码符合HarmonyOS NEXT API 14的规范。为了方便初学者更好入门&#xff0c;V 哥伙同2位小伙伴花了1年时间&#xff0c;搞了三本鸿蒙…...

视频智能分析网关助力小区/住宅/街道智慧社区管理服务全面升级

一、引言​ 随着信息技术的飞速发展&#xff0c;智慧社区建设已成为提升居民生活质量、优化社区管理的重要趋势。智能分析网关作为智慧社区的核心技术支撑之一&#xff0c;凭借其强大的数据处理和智能分析能力&#xff0c;在社区的安防监控、人员车辆管理、环境卫生检测等多个…...

ShardingJdbc-水平分表

ShardingJdbc-水平分表 水平分表 表结构相同表数据记录不同多张分表记录数和才是总的记录数通常根据主键ID进行分表&#xff0c;这里采用奇偶策略 案例 建立库 sharding-demo建立表 user_1、user_2 表结构相同id 为主键&#xff0c;bigint 类型分表规则 id 为偶数的记录存储…...

AI应用爆发或将进入临界点

在科技发展的长河中,总有一些时刻如惊雷般震撼世界,预示着新时代的到来。如今,AI应用似乎正站在这样一个关键节点上,一场前所未有的变革风暴或许即将席卷而来,AI应用的爆发或将进入临界点。 当我们回顾科技发展的历程,不难发现每一次重大的技术突破都曾引发社会的巨大变…...

Javase 基础加强 —— 05 Map集合

本系列为笔者学习Javase的课堂笔记&#xff0c;视频资源为B站黑马程序员出品的《黑马程序员JavaAI智能辅助编程全套视频教程&#xff0c;java零基础入门到大牛一套通关》&#xff0c;章节分布参考视频教程&#xff0c;为同样学习Javase系列课程的同学们提供参考。 01 概述 Ma…...

LINUX——例行性工作

单一执行的例行性工作 仅处理一次的工作&#xff0c;可用于在特定时间执行工作 at命令的工作过程&#xff1a; at命令使用时的权限控制&#xff1a;通过两个文件/etc/at.allow和/etc/at.deny来控制哪些用户可以使用at命令。如果这两个文件都不存在&#xff0c;那么只有root用户…...

天线测试报告解读学习

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、无源测试和有源测试二、无源测试报告1.驻波2.回损3.史密斯圆图4.效率5.增益6.天线方向图7.天线隔离度8.无源测试总结 三、有源测试报告1.TRP与TIS2.测试指标…...

Kotlin Android开发过渡指南

为了帮助Java开发者顺利过渡到Kotlin进行Android开发,以下是一本指南的详细大纲设计,涵盖关键知识点、迁移策略和实践案例: 《Kotlin for Android开发:从Java到Kotlin的平滑过渡指南》大纲 第一部分:为什么选择Kotlin? Kotlin的优势 简洁性、安全性、与Java的互操作性Go…...

Hadoop架构再探讨

文章目录 1.Hadoop的优化与发展1.1Hadoop的局限与不足1.2针对Hadoop的改进与提升 2.HDFS2.0新特性2.1HDFS HA1.HDFS 1.0 组件及功能回顾​2. HDFS 1.0 的单点故障问题​3. HDFS HA&#xff08;高可用&#xff09;解决方案​ 2.2HDFS Federation1.HDFS1.0中存在的问题2.HDFS Fed…...

ffmpeg录音测试

ffmpeg ffmpeg 是一个强大的多媒体处理工具&#xff0c;可以用于录音、音频处理、视频录制等多种功能。以下是使用 ffmpeg 进行录音的详细指令和参数说明。 基本录音指令 以下是一个简单的 ffmpeg 录音命令&#xff0c;将音频录制为 WAV 格式文件&#xff1a; ffmpeg -f …...

Kotlin-解构声明

我们在使用对象时可能需要访问它们内部的一些属性: class Student(var name: String, var age: Int) fun main() {val student Student("小明", 18)println(student.name)println(student.age) }这样看起来不太优雅,我们可以像下面这样编写: class Student(var na…...

【MCP Node.js SDK 全栈进阶指南】专家篇(2):MCP多模型支持架构

引言 在实际应用中,单一模型往往难以满足所有业务需求,这就需要一种灵活的架构来支持多模型集成和智能调度。Model Context Protocol (MCP) 作为连接应用与AI模型的标准协议,为多模型支持提供了理想的基础架构。 本文作将深入探讨如何基于MCP构建多模型支持架构,包括多LL…...

使用阿里AI的API接口实现图片内容提取功能

参考链接地址&#xff1a;如何使用Qwen-VL模型_大模型服务平台百炼(Model Studio)-阿里云帮助中心 在windows下&#xff0c;使用python语言测试&#xff0c;版本&#xff1a;Python 3.8.9 一. 使用QVQ模型解决图片数学难题 import os import base64 import requests# base 64 …...

mapbox基础,加载Fog云雾效果

👨‍⚕️ 主页: gis分享者 👨‍⚕️ 感谢各位大佬 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍⚕️ 收录于专栏:mapbox 从入门到精通 文章目录 一、🍀前言1.1 ☘️mapboxgl.Map 地图对象1.2 ☘️mapboxgl.Map style属性1.3 ☘️fog 云雾 api1.3.1 ☘️配置项二、🍀…...

数据可视化与分析

数据可视化的目的是为了数据分析&#xff0c;而非仅仅是数据的图形化展示。 项目介绍 项目案例为电商双11美妆数据分析&#xff0c;分析品牌销售量、性价比等。 数据集包括更新日期、ID、title、品牌名、克数容量、价格、销售数量、评论数量、店名等信息。 1、数据初步了解…...

git的push.default配置详解

Git的push.default配置用于定义执行git push时未指定远程和分支的默认行为。以下是各选项的详解及使用场景&#xff1a; 1. simple&#xff08;默认值&#xff0c;Git ≥2.0&#xff09; 行为&#xff1a;仅推送当前分支到与其关联的上游分支&#xff08;即remote-tracked分支…...

高频电流探头:通信测试中的隐形守护者

在5G基站调试现场&#xff0c;工程师李工正手持一个火柴盒大小的装置贴近电路板&#xff0c;示波器屏幕上瞬间显示出精确的电流波形——这个看似普通的场景&#xff0c;背后折射出高频电流探头在通信测试中的关键作用。随着通信技术迈入毫米波时代&#xff0c;这类精密测试工具…...

淘宝拍立淘 API 接口探秘:如何通过图片挖掘海量商品信息

在互联网技术飞速发展的当下&#xff0c;传统的文字搜索商品方式已无法完全满足用户日益增长的个性化需求。基于图像识别技术的以图搜物模式应运而生&#xff0c;成为电商行业的新宠。淘宝拍立淘 API 接口作为这一技术的重要载体&#xff0c;能够帮助开发者和企业通过一张图片&…...

第二章:langchain文本向量化(embed)搭建与详细教程-本地服务方式(下)

文章目录 前言一、本地构建模型与服务端搭建代码1、完整代码2、结果示例 二、基于flask服务端构建langchain调用的向量方法代码1、完整代码2、结果示例 总结 前言 在上篇文章介绍了langchain源码embed方法与基于api key方式构建向量模型。然而&#xff0c;某些情况&#xff0c…...

飞牛云如何开启及使用ssh:小白用户上手指南-家庭云计算专家

最近很多用户希望提供飞牛云下的可道云onlyoffice的安装服务,但是很多都是萌新小白,不知道怎么启用ssh和使用ssh客户端.这里提供简单的方法,统一答复: 重要的事情说3遍:一定不要自己发挥,全部按说明的来;一定要在内网环境用内网ip访问;不要用域名和端口号,谢谢各位萌新了!!! 一…...

12.模方ModelFun工具-立面修整

摘要&#xff1a;本文主要介绍模方ModelFun修模工具——立面修整的操作方法。 点击工具栏即可找到立面修整工具&#xff0c;点击可打开并使用该工具&#xff0c;如下图&#xff1a; 图 工具菜单栏 &#xff08;1&#xff09;截面绘制&#xff1a; 快速绘制竖直矩形&#xff1…...

消失的两个数字 --- 位运算

目录 一&#xff1a;题目 二&#xff1a;算法原理 三&#xff1a;代码实现 一&#xff1a;题目 题目链接&#xff1a;面试题 17.19. 消失的两个数字 - 力扣&#xff08;LeetCode&#xff09; 二&#xff1a;算法原理 只出现一次的数字III&#xff1a;常见位运算总结-CSDN…...

centos的根目录占了大量空间怎么办

问题 当根目录磁盘不够时&#xff0c;就必须删除无用的文件了 上面的&#xff0c;如果删除/usr 或/var是可以释放出系统盘的 定位占空间大的文件 经过命令&#xff0c;一层层查哪些是占磁盘的。 du -sh /* | sort -rh | head -n 10 最终排查&#xff0c;是有个系统日志占了20…...

Protobuf的速成之旅

注意事项:本文使用Linux下的Ubuntu C/C 一.Protobuf的安装 在安装Protobuf前需要先安装protobuf的依赖库 sudo apt-get install autoconf automake libtool curl make g unzip -y Protobuf的安装链接:https://github.com/protocolbuffers/protobuf/releases 这里根据自己的环…...