React(九)React Hooks

news2025/7/12 8:18:15

初识Hook

我们到底为什么需要hook那?

函数组件类组件存在问题

函数组件存在的问题:

import React, { PureComponent } from 'react'

function HelloWorld2(props) {
  let message="Hello world"

  // 函数式组件存在的缺陷:
  // 1.修改message之后,组件不会重新渲染
  // 2.就算页面重新渲染:函数会被重新执行,第二次执行时,又会重新给message赋值未Hello world
  // 3.不能编写类似生命周期的回调:网络请求...
  return (
    <div>
      <h1 onClick={e =>message="你好啊"}>内容2:{message}</h1>
      <button>修改文本</button>
    </div>
  )
}
export class App extends PureComponent {
  render() {
    return (
      <div>
        <h1>App</h1>
        <hr />
        <HelloWorld2 />
      </div>
    )
  }
}

export default App

class组件存在的问题:

1.复杂组件变得难以理解

  • 随着业务增加,class组件会变得越来越复杂
  • 在挂载阶段,可能包含大量的逻辑代码:网络请求、事件监听等;还得在卸载阶段移除掉
  • 逻辑往往混在一起,class难以拆分

2.更加复杂:需要搞清this的指向到底是谁,熟练ES6class

3.组件复用难

  • 状态复用需要通过高阶组件
  • 或者类似Provider、Consumer来共享一些状态,但多次使用Consumer,会导致我们代码存在很多嵌套,难以维护

Hook的出现

hooks的出现就是为了解决上述问题:

  • 它可以在不编写class的情况下使用state以及其它React特性
  • 基本可替代之前所有使用class组件的地方
  • 并不需要直接将所有的代码重构为hooks,因为它向下兼容,可渐进式使用它
  • 只能在函数组件中使用,不能在类组件中使用

Hook实现计数器

 

import React, { memo,useState } from 'react'
// useState()返回的是一个数组
// 元素一:当前状态的值(第一次为初始值),如果不设置则为undefined
// 元素二:更新当前值的函数
const CounterFunction = memo(() => {
  const [counter,setCounter] = useState(0)
  return (
    <div>
      <h2>CounterFunction:{counter}</h2>
      <button onClick={e => setCounter(counter+1)}>+1</button>
      <button onClick={e => setCounter(counter-1)}>-1</button>
    </div>
  )
})

export default CounterFunction

State/Effect

useState

1.useState来自react,需要从react中导入,它是一个hook;

  • 参数:初始化值,如果不设置为undefined;
  • 返回值:数组,包含两个元素;
  • 元素一:当前状态的值(第一调用为初始化值);
  • 元素二:设置状态值的函数;

2.点击button按钮后,会完成两件事情:

  • 调用setCount,设置一个新的值;
  • 组件重新渲染,并且根据新的值返回DOM结构;

3.Hook 就是 JavaScript 函数,这个函数可以帮助你 钩入(hook into) React State以及生命周期等特性;

4.但是使用它们会有两个额外的规则:

  • 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用
  • 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用

如果逻辑太复杂,也可以单独封装一个函数修改数据

import React, { memo,useState } from 'react'

const CounterFunction = memo(() => {
  const [message,setMessage] = useState("HelloWorld")

  function changeMessage(){
    setMessage("你好呀")
  }
  return (
    <div>
      <h2>CounterFunction:{message}</h2>
      <button onClick={changeMessage}>修改文本</button>
    </div>
  )
})

export default CounterFunction

注意:为什么是useState而不是createState?

解答:因为state只在组件首次渲染时被创建,在下次渲染时,useState返回给我们当前的state。如果每次都创建新的变量,那就不该是状态了。

useEffect

它可以帮在函数组件中完成类似于class生命周期的功能。如网络请求、手动更新DOM、一些事件的监听,都是React更新DOM的一些副作用(Side Effects)。因此对于完成这些功能的Hook就被称为Effect Hook

1.基本使用

我们现在来完成一个需求:使页面的title总是显示count的数字:

 

代码实现:

 

useEffect传入一个回调函数, 这个回调函数在每次页面渲染完成后自动执行。也就是说,每次在函数式组件执行的顺序是:

执行函数组件 => 定义初始状态 => 渲染DOM => 执行useEffect中的回调=> 修改数据 => 重新执行函数组件 => 更新状态 => 渲染最新DOM => 执行useEffect中的回调

不难看出,其实useEffect中的回调相当于完成了componentDidMount和componentDidUpdate做的事情。

2.清除Effect

在类组件编写过程中,某些副作用我们需要在componentWillUnmount中进行清除,如事件总线、Redux中手动调用的subscribe等

useEffect传入的回调函数A本身有一个返回值,返回值里面是回调函数B,可在函数B中进行清除

// 复杂告知react,在执行完当前渲染之后要执行的副作用代码
useEffect(() => {
  console.log("监听redux中数据变化");

  // 传入的回调函数,又会返回一个回调函数=> 组件被重新渲染或卸载时执行
  return () => {
    console.log("取消监听redux中的数据变化");
  }
})

3.使用多个Effect

将这些处理逻辑都放在同一个函数里面难维护,要清除也比较混乱,在使用中我们可将逻辑分离到不同的useEffect中:React 将按照 effect 声明的顺序依次调用组件中的每一个 effect;

如下图:

 

但是有一个问题,难道每渲染一次页面,我们的所有effect就要重新调用一次吗?

某些逻辑只需要执行一次即可,怎样才能解决这个问题嘞?

实际上,Effect有两个参数:

  • 参数一:执行的回调函数;
  • 参数二:该useEffect在哪些state发生变化时,才重新执行;(受谁的影响)
import React, { memo, useEffect, useState } from 'react'

const App = memo(() => {
  const [count,setCount] = useState(0)
  const [message,setMessage] = useState("HelloWorld")

  useEffect(() => {
    console.log("修改title");
  },[count])

  useEffect(() => {
    console.log("监听redux中的数据");
    return () => {
    }
  },[])

  useEffect(() => {
    console.log("监听eventBus的why事件");
    return () => {
    }
  },[])

  // 我希望它第一次渲染时执行一次即可
  useEffect(() => {
    console.log("发生网络请求");
    return () => {
      console.log("会在我们组件被卸载时才会执行");
    }
  },[]) 

  return (
    <div>
      <h2>Count-{count} </h2>
      <button onClick={e => setCount(count+1)}>+1</button>
      <button onClick={e => setMessage("你好啊")}>message({message})</button>
    </div>
  )
})

export default App

打印结果如下图:

 

Context/Reducer

useContext

我们之前在组件中使用类名.contextType = MyContext或MyContext.Consumer来共享数据

但是当多个Context共享时就会存在大量的嵌套:

import React, { Component } from 'react'
import { UserContext,ThemeContext } from './context'

export default class App extends Component {
  // 使用Conetxt
  render() {
    return (
      <div>
        <UserContext.Consumer>
          {
            value => {
              return (
                <h2><ThemeContext.Consumer>
                  {value => <span>{value.color}</span>}
                  </ThemeContext.Consumer> </h2>
              )
            }
          }
        </UserContext.Consumer>
      </div>
    )
  }
}

Context Hook允许我们通过Hook来直接获取某个Context的值

import React, { memo ,useContext} from 'react'
import { UserContext,ThemeContext } from './context'

const App = memo(() => {
  // 使用Conetxt
  const user = useContext(UserContext)
  const theme = useContext(ThemeContext)
  return (
    <div>
      <div>
        <span>用户信息-{user.name}-{user.age} </span>
        <span>主题色-{theme.color} </span>
      </div>
    </div>
  )
})

export default App

注意:当组件上层最近的 <MyContext.Provider> 更新时,该 Hook 会触发重新渲染,并使用最新传递给 MyContext provider 的context value 值。因此,该数据的更新也是响应式的。

Callback/Memo(性能优化)

useCallback

通常使用useCallback是不希望子组件进行多次渲染,并不是为了进行函数缓存

1.存在问题

 

import React, { memo,useCallback,useState } from 'react'

const HYHome = memo(function(props) {
  const { increment } = props
  console.log("HYHome被渲染")
  return (
    <div>
      <button onClick={increment}>increment+8</button>

      {/* 100个子组件 */}
    </div>
  )
})

const App = memo(() => {
  const [count, setCount] = useState(0)

  const increment = function() {
    console.log("increment");
    setCount(count + 8)
  }

  return (
    <div>
      <h2>App-{count}</h2>
      <button onClick={increment} >+8</button>
      <HYHome increment={increment}/>
    </div>
  )
})

export default App

我希望当子组件没有变化时,不需要重新渲染:

useCallback()返回一个函数的记忆值,在依赖不变的情况下,多次定义返回值是相同的

import React, { memo, useState, useCallback, useRef } from 'react'

// useCallback性能优化的点:
// 1.当需要将一个函数传递给子组件时, 最好使用useCallback进行优化, 将优化之后的函数, 传递给子组件——这样的话在某些情况下,子组件就不会重新渲染

// props中的属性发生改变时, 组件本身就会被重新渲染
const HYHome = memo(function(props) {
  const { increment } = props
  console.log("HYHome被渲染")
  return (
    <div>
      <button onClick={increment}>increment+1</button>

      {/* 100个子组件 */}
    </div>
  )
})

const App = memo(function() {
  const [count, setCount] = useState(0)
  const [message, setMessage] = useState("hello")

  // 闭包陷阱: useCallback
  // const increment = useCallback(function foo() {
  //   console.log("increment")
  //   setCount(count+1)
  // }, [count])

  // 进一步的优化: 当count发生改变时, 也使用同一个函数(了解)
  // 做法一: 将count依赖移除掉, 缺点: 闭包陷阱
  // 做法二: useRef, 在组件多次渲染时, 返回的是同一个值
  const countRef = useRef()
  countRef.current = count
  const increment = useCallback(function foo() {
    console.log("increment")
    setCount(countRef.current + 1)
  }, [])

  // 普通的函数
  // const increment = () => {
  //   setCount(count+1)
  // }

  return (
    <div>
      <h2>计数: {count}</h2>
      <button onClick={increment}>+1</button>

      <HYHome increment={increment}/>

      <h2>message:{message}</h2>
      <button onClick={e => setMessage(Math.random())}>修改message</button>
    </div>
  )
})

export default App

useMemo

1.使用场景:

  • 有大量逻辑计算时,若逻辑输入值无变化,则无需重新计算
  • 对子组件传递相同内容对象时,若无改变则不重新执行

2.函数传入两个参数:

参数一:回调函数

参数二:[逻辑执行依赖的变量]

3.useMemo和useCallback的对比

useMemo拿到的是传入回调函数的返回值,useCallback是回调函数本身

import React, { memo, useCallback } from 'react'
import { useMemo, useState } from 'react'


const HelloWorld = memo(function(props) {
  console.log("HelloWorld被渲染~")
  return <h2>Hello World</h2>
})


// 计算数字
function calcNumTotal(num) {
  // console.log("calcNumTotal的计算过程被调用~")
  let total = 0
  for (let i = 1; i <= num; i++) {
    total += i
  }
  return total
}

const App = memo(() => {
  const [count, setCount] = useState(0)

  // const result = calcNumTotal(50)

  // 1.不依赖任何的值, 进行计算
  const result = useMemo(() => {
    return calcNumTotal(50)
  }, [])

  // 2.依赖count
  // const result = useMemo(() => {
  //   return calcNumTotal(count*2)
  // }, [count])

  // 3.useMemo和useCallback的对比
  function fn() {}
  // const increment = useCallback(fn, [])
  // const increment2 = useMemo(() => fn, [])


  // 4.使用useMemo对子组件渲染进行优化
  // 重新渲染时会定义一个新对象,传入值是没有什么区别的
  // const info = { name: "why", age: 18 }
  const info = useMemo(() => ({name: "why", age: 18}), [])

  return (
    <div>
      <h2>计算结果: {result}</h2>
      <h2>计数器: {count}</h2>
      <button onClick={e => setCount(count+1)}>+1</button>

      <HelloWorld result={result} info={info} />
    </div>
  )
})

export default App

Ref/LayoutEffect

useRef

1.获取DOM

import React, { memo, useRef } from 'react'

const App = memo(() => {
  const titleRef = useRef()
  const inputRef = useRef()

  function showTitleDom() {
    console.log(titleRef.current)
    inputRef.current.focus()
  }

  return (
    <div>
      <h2 ref={titleRef}>Hello World</h2>
      <input type="text" ref={inputRef} />
      <button onClick={showTitleDom}>查看title的dom</button>
    </div>
  )
})

export default App

2.useRef解决闭包陷阱问题

useRef返回一个ref对象,返回的ref对象再组件的整个生命周期保持不变

import React, { memo, useRef } from 'react'
import { useCallback } from 'react'
import { useState } from 'react'

let obj = null

const App = memo(() => {
  const [count, setCount] = useState(0)
  // useRef返回的是一个不变的对象(地址不变)
  const nameRef = useRef()
  console.log(obj === nameRef)
  obj = nameRef

  // 通过useRef解决闭包陷阱
  const countRef = useRef()
  countRef.current = count

  const increment = useCallback(() => {
    setCount(countRef.current + 1)
  }, [])

  return (
    <div>
      <h2>Hello World: {count}</h2>
      <button onClick={e => setCount(count+1)}>+1</button>
      <button onClick={increment}>+1</button>
    </div>
  )
})

export default App

useImperativeHandle/useLayoutEffect(了解)

useImperativeHandle

通过forwardRef可以将子组件的DOM直接暴露给父组件,但是这样也产生了一些问题:

父组件可以拿到子组件的DOM进行任意操作,这样就有点危险了,我们有什么办法解决吗?

  • 可以通过useImperativeHandle的Hook,将传入的ref和useImperativeHandle第二个参数返回的对象绑定到了一起
  • 在父组件中,使用 inputRef.current时,实际上使用的是返回的对象

代码示例:

import React, { memo, useRef, forwardRef, useImperativeHandle } from 'react'



const HelloWorld = memo(forwardRef((props, ref) => {

  const inputRef = useRef()

  // 如果直接绑定它,权限有点多,对于子组件来说太危险了——我希望只给它保留特定的权限
  // 子组件对父组件传入的ref进行处理
  useImperativeHandle(ref, () => {
    return {
      focus() {
        console.log("focus")
        inputRef.current.focus()
      },
      setValue(value) {
        inputRef.current.value = value
      }
    }
  })

  return <input type="text" ref={inputRef}/>
}))


const App = memo(() => {
  const titleRef = useRef()
  const inputRef = useRef()

  function handleDOM() {
    // console.log(inputRef.current)
    inputRef.current.focus()
    // inputRef.current.value = ""
    inputRef.current.setValue("哈哈哈")
  }

  return (
    <div>
      <h2 ref={titleRef}>哈哈哈</h2>
      <HelloWorld ref={inputRef}/>
      <button onClick={handleDOM}>DOM操作</button>
    </div>
  )
})

export default App

useLayoutEffect

useLayoutEffect看起来和useEffect非常的相似,事实上他们也只有一点区别而已:

  • useEffect会在渲染的内容更新到DOM上后执行,不会阻塞DOM的更新;
  • useLayoutEffect会在渲染的内容更新到DOM上之前执行,会阻塞DOM的更新;

如果我们希望在某些操作发生之后再更新DOM,那么应该将这个操作放到useLayoutEffect。

import React, { memo, useEffect, useLayoutEffect, useState } from 'react'

const App = memo(() => {
  const [count, setCount] = useState(100)

  // 点击按钮后,会出现闪烁现象-先变成0,再变成99.xxxx,
  useEffect(() => {
    console.log("useEffect")
    if (count === 0) {
      setCount(Math.random() + 99)
    }
  })

  // 不会出现闪烁现象,直接变成99.xxxx
  useLayoutEffect(() => {
    console.log("useLayoutEffect")
    if (count === 0) {
      setCount(Math.random() + 99)
    }
  })

  console.log("App render")

  return (
    <div>
      <h2>count: {count}</h2>
      <button onClick={e => setCount(0)}>设置为0</button>
    </div>
  )
})

export default App

自定义Hook

本质:对函数代码的抽取,实现复用,减少代码逻辑

需求一:所有的组件在创建和销毁时都进行打印

import React, { memo, useEffect, useState } from 'react'

// 自定义Hook
function useLogLife(cName) {
  useEffect(() => {
    console.log(cName + "组件被创建")
    return () => {
      console.log(cName + "组件被销毁")
    }
  }, [cName])
}

const Home = memo(() => {
  useLogLife("home")

  return <h1>Home Page</h1>
})

const About = memo(() => {
  useLogLife("about")

  return <h1>About Page</h1>
})

const App = memo(() => {
  const [isShow, setIsShow] = useState(true)

  useLogLife("app")

  return (
    <div>
      <h1>App Root Component</h1>
      <button onClick={e => setIsShow(!isShow)}>切换</button>
      { isShow && <Home/> }
      { isShow && <About/> }
    </div>
  )
})

export default App

需求二:Context的共享

1.有两个自定义的context

import { createContext } from "react";

const UserContext = createContext()
const TokenContext = createContext()

export {
  UserContext,
  TokenContext
}

2.通过.Provider去包裹根组件

root.render(
  <userContext.Provider value={{name:'dimple', age: 22}}>
    <tokenContext.Provider value={'dimple555'}>
      <App />
    </tokenContext.Provider>
  </userContext.Provider>
);

3.封装一个hook方法,只要一调用就能拿到共享的数据

import { useContext } from "react"
import { UserContext, TokenContext } from "../context"

function useUserToken() {
  const user = useContext(UserContext)
  const token = useContext(TokenContext)

  return [user, token]
}

export default useUserToken

4.在子组件中使用

import React, { memo } from 'react'
import { useUserToken } from "./hooks"

// User/Token

const Home = memo(() => {
  const [user, token] = useUserToken()

  return <h1>Home Page: {user.name}-{token}</h1>
})

const About = memo(() => {
  const [user, token] = useUserToken()

  return <h1>About Page: {user.name}-{token}</h1>
})

const App = memo(() => {
  return (
    <div>
      <h1>App Root Component</h1>
      <Home/>
      <About/>
    </div>
  )
})

export default App

需求三:获取鼠标滚动位置

1.定义一个hook

import { useState, useEffect } from "react"

function useScrollPosition() {
  const [ scrollX, setScrollX ] = useState(0)
  const [ scrollY, setScrollY ] = useState(0)

  useEffect(() => {
    function handleScroll() {
      // console.log(window.scrollX, window.scrollY)
      setScrollX(window.scrollX)
      setScrollY(window.scrollY)
    }

    window.addEventListener("scroll", handleScroll)
    //使用完销毁
    return () => {
      window.removeEventListener("scroll", handleScroll)
    }
  }, [])

  return [scrollX, scrollY]
}

export default useScrollPosition

2.在各个组件中使用

import React, { memo } from 'react'
import useScrollPosition from './hooks/useScrollPosition'
import "./style.css"

const Home = memo(() => {
  const [scrollX, scrollY] = useScrollPosition()

  return <h1>Home Page: {scrollX}-{scrollY}</h1>
})

const About = memo(() => {
  const [scrollX, scrollY] = useScrollPosition()

  return <h1>About Page: {scrollX}-{scrollY}</h1>
})

const App = memo(() => {
  return (
    <div className='app'>
      <h1>App Root Component</h1>
      <Home/>
      <About/>
    </div>
  )
})

export default App

redux hooks

在redux开发中,我们为了让组件和redux结合起来,我们使用了react-redux的connect,这种方式必须使用高阶函数结合返回的高阶组件,且必须编写mapStateToProps和mapDispatchToProps映射的函数,这样其实挺麻烦的

Redux7.1开始,可获取仓库的数据和方法

useSelector:将store映射到组件中

参数一:传入一个回调函数,参数为state,返回需要的数据对象

参数二:通过比较决定组件是否重新渲染

import React, { memo } from 'react'
import { useSelector, useDispatch, shallowEqual } from "react-redux"
import { addNumberAction, changeMessageAction, subNumberAction } from './store/modules/counter'


// memo高阶组件包裹起来的组件有对应的特点: 只有props发生改变时, 才会重新渲染
//它默认会比较比较返回的两个对象是否相等,也就是必须返回两个完全相等的对象才可以不引起重新渲染
//那比如message属性值没发生改变就不该渲染该组件的,所以加了shallowEqual
const Home = memo((props) => {
  const { message } = useSelector((state) => ({
    message: state.counter.message
  }), shallowEqual)

  const dispatch = useDispatch()
  function changeMessageHandle() {
    dispatch(changeMessageAction("你好啊, 师姐!"))
  }

  console.log("Home render")

  return (
    <div>
      <h2>Home: {message}</h2>
      <button onClick={e => changeMessageHandle()}>修改message</button>
    </div>
  )
})


const App = memo((props) => {
  // 1.使用useSelector将redux中store的数据映射到组件内
  const { count } = useSelector((state) => ({
    count: state.counter.count
  }), shallowEqual)

  // 2.使用dispatch直接派发action
  const dispatch = useDispatch()
  function addNumberHandle(num, isAdd = true) {
    if (isAdd) {
      dispatch(addNumberAction(num))
    } else {
      dispatch(subNumberAction(num))
    }
  }

  console.log("App render")

  return (
    <div>
      <h2>当前计数: {count}</h2>
      <button onClick={e => addNumberHandle(1)}>+1</button>
      <button onClick={e => addNumberHandle(6)}>+6</button>
      <button onClick={e => addNumberHandle(6, false)}>-6</button>

      <Home/>
    </div>
  )
})

export default App

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2327886.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《AI大模型应知应会100篇》加餐篇:LlamaIndex 与 LangChain 的无缝集成

加餐篇&#xff1a;LlamaIndex 与 LangChain 的无缝集成 问题背景&#xff1a;在实际应用中&#xff0c;开发者常常需要结合多个框架的优势。例如&#xff0c;使用 LangChain 管理复杂的业务逻辑链&#xff0c;同时利用 LlamaIndex 的高效索引和检索能力构建知识库。本文在基于…

元素三大等待

硬性等待&#xff08;强制等待&#xff09; 线程休眠&#xff0c;强制等待 Thread.sleep(long millis);这是最简单的等待方式&#xff0c;使用time.sleep()方法来实现。在代码中强制等待一定的时间&#xff0c;不论元素是否已经加载完成&#xff0c;都会等待指定的时间后才继…

【DY】信息化集成化信号采集与处理系统;生物信号采集处理系统一体机

MD3000-C信息化一体机生物信号采集处理系统 实验平台技术指标 01、整机外形尺寸&#xff1a;1680mm(L)*750mm(w)*2260mm(H)&#xff1b; 02、实验台操作面积&#xff1a;750(w)*1340(L&#xff09;&#xff08;长*宽&#xff09;&#xff1b; 03、实验台面离地高度&#xf…

康谋分享 | 仿真驱动、数据自造:巧用合成数据重构智能座舱

随着汽车向智能化、场景化加速演进&#xff0c;智能座舱已成为人车交互的核心承载。从驾驶员注意力监测到儿童遗留检测&#xff0c;从乘员识别到安全带状态判断&#xff0c;座舱内的每一次行为都蕴含着巨大的安全与体验价值。 然而&#xff0c;这些感知系统要在多样驾驶行为、…

Vue 数据传递流程图指南

今天&#xff0c;我们探讨一下 Vue 中的组件传值问题。这不仅是我们在日常开发中经常遇到的核心问题&#xff0c;也是面试过程中经常被问到的重要知识点。无论你是初学者还是有一定经验的开发者&#xff0c;掌握这些传值方式都将帮助你更高效地构建和维护 Vue 应用 目录 1. 父…

【C语言】strstr查找字符串函数

一、函数介绍 strstr 是 C 语言标准库 <string.h> 中的字符串查找函数&#xff0c;用于在主字符串中查找子字符串的首次出现位置。若找到子串&#xff0c;返回其首次出现的地址&#xff1b;否则返回 NULL。它是处理字符串匹配问题的核心工具之一。 二、函数原型 char …

机器学习、深度学习和神经网络

机器学习、深度学习和神经网络 术语及相关概念 在深入了解人工智能&#xff08;AI&#xff09;的工作原理以及它的各种应用之前&#xff0c;让我们先区分一下与AI密切相关的一些术语和概念&#xff1a;人工智能、机器学习、深度学习和神经网络。这些术语有时会被交替使用&#…

数字孪生在智慧城市中的前端呈现与 UI 设计思路

一、数字孪生技术在智慧城市中的应用与前端呈现 数字孪生技术通过创建城市的虚拟副本&#xff0c;实现了对城市运行状态的实时监控、分析与预测。在智慧城市中&#xff0c;数字孪生技术的应用包括交通流量监测、环境质量分析、基础设施管理等。其前端呈现主要依赖于Web3D技术、…

Android OpenGLES 360全景图片渲染(球体内部)

概述 360度全景图是一种虚拟现实技术&#xff0c;它通过对现实场景进行多角度拍摄后&#xff0c;利用计算机软件将这些照片拼接成一个完整的全景图像。这种技术能够让观看者在虚拟环境中以交互的方式查看整个周围环境&#xff0c;就好像他们真的站在那个位置一样。在Android设备…

LETTERS(DFS)

【题目描述】 给出一个rowcolrowcol的大写字母矩阵&#xff0c;一开始的位置为左上角&#xff0c;你可以向上下左右四个方向移动&#xff0c;并且不能移向曾经经过的字母。问最多可以经过几个字母。 【输入】 第一行&#xff0c;输入字母矩阵行数RR和列数SS&#xff0c;1≤R,S≤…

NVM 多版本Node.js 管理全指南(Windows系统)

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、全栈领域优质创作者、高级开发工程师、高级信息系统项目管理师、系统架构师&#xff0c;数学与应用数学专业&#xff0c;10年以上多种混合语言开发经验&#xff0c;从事DICOM医学影像开发领域多年&#xff0c;熟悉DICOM协议及…

C,C++语言缓冲区溢出的产生和预防

缓冲区溢出的定义 缓冲区是内存中用于存储数据的一块连续区域&#xff0c;在 C 和 C 里&#xff0c;常使用数组、指针等方式来操作缓冲区。而缓冲区溢出指的是当程序向缓冲区写入的数据量超出了该缓冲区本身能够容纳的最大数据量时&#xff0c;额外的数据就会覆盖相邻的内存区…

《Linux内存管理:实验驱动的深度探索》【附录】【实验环境搭建 2】【vscode搭建调试内核环境】

1. 如何调试我们的内核 1. GDB调试 安装gdb sudo apt-get install gdb-multiarchgdb-multiarch是多架构版本&#xff0c;可以通过set architecture aarch64指定架构 QEMU参数修改添加-s -S #!/usr/bin/shqemu-7.2.0-rc1/build/aarch64-softmmu/qemu-system-aarch64 \-nogr…

Flutter项目之登录注册功能实现

目录&#xff1a; 1、页面效果2、登录两种状态界面3、中间按钮部分4、广告区域5、最新资讯6、登录注册页联调6.1、网络请求工具类6.2、注册页联调6.3、登录问题分析6.4、本地缓存6.5、共享token6.6、登录页联调6.7、退出登录 1、页面效果 import package:flutter/material.dart…

ctfshow VIP题目限免 源码泄露

根据题目提示是源代码泄露&#xff0c;右键查看页面源代码发现了 flag

移动神器RAX3000M路由器变身家庭云之七:增加打印服务,电脑手机无线打印

系列文章目录&#xff1a; 移动神器RAX3000M路由器变身家庭云之一&#xff1a;开通SSH&#xff0c;安装新软件包 移动神器RAX3000M路由器变身家庭云之二&#xff1a;安装vsftpd 移动神器RAX3000M路由器变身家庭云之三&#xff1a;外网访问家庭云 移动神器RAX3000M路由器不刷固…

《函数基础与内存机制深度剖析:从 return 语句到各类经典编程题详解》

一、问答题 &#xff08;1&#xff09;使用函数的好处是什么&#xff1f; 1.提升代码的复用性 2.提升代码的可维护性 3.增强代码的可读性 4.提高代码的灵活性 5.方便进行单元测试 &#xff08;2&#xff09;如何定义一个函数&#xff1f;如何调用一个函数&#xff1f; 在Pytho…

Python | 使用Matplotlib绘制Swarm Plot(蜂群图)

Swarm Plot&#xff08;蜂群图&#xff09;是一种数据可视化图表&#xff0c;它用于展示分类数据的分布情况。这种图表通过将数据点沿着一个或多个分类变量轻微地分散&#xff0c;以避免它们之间的重叠&#xff0c;从而更好地显示数据的分布密度和分布趋势。Swarm Plot特别适用…

新版本Xmind结合DeepSeek快速生成美丽的思维导图

前言 我的上一篇博客&#xff08;https://quickrubber.blog.csdn.net/article/details/146518898&#xff09;中讲到采用Python编程可以实现和Xmind的互动&#xff0c;并让DeepSeek来生成相应的代码从而实现对内容的任意修改。但是&#xff0c;那篇博客中提到的Xmind有版本的限…

set和map封装

目录 set和map区别 set和map的插入 set和map的实现 修改红黑树的模板参数 修改比较时使用的变量 迭代器的实现 迭代器的定义 *解引用重载 ->成员访问重载 自增重载 重载 封装迭代器 RBTree迭代器封装 封装set迭代器 对set迭代器进行修改 封装map迭代器 修改…