一天搞定React(3)——Hoots组件【已完结】

    Hello!大家好,今天带来的是React前端JS库的学习,课程来自黑马的往期课程,具体连接地址我也没有找到,大家可以广搜巡查一下,但是总体来说,这套课程教学质量非常高,每个知识点都有一个小案例,最后有一个总的美团外卖案例教学,大家可以看看我这篇文章,如果能够帮到你们,还请多多点赞o( ̄▽ ̄)d支持支持🌹,如果文章中有错误的或者是遗漏信息,可以在评论区指出或者是与我私信。我看到了消息,一定会及时更正过来∠(°ゝ°)。话不多说,直接开学💪⛽️!

     本篇教学已完结,具体可查看教程:
1. 一天搞定React(1)——React安装与配置
2. 一天搞定React(2)——JSX语法
3. 一天搞定React(3)——Hoots组件
4. 一天搞定React(4)——Redux
5. 一天搞定Recat(5)——ReactRouter(上)
6. 一天搞定React(5)——ReactRouter(下)

文章目录

  • 组件学习
    • 创建组件
    • 组件的状态
      • 修改状态
        • 【案例】B站评论
        • classNames优化
      • 状态操作表单元素
    • useRef
  • 组件通讯
    • 父子组件通讯
      • 父传子通讯
      • 简化props
    • 子到父通讯
    • 非父子通讯
      • 兄弟关系
      • 后代关系
  • useEffet的使用
    • useEffect扩展
    • useEffect应用——发送请求
      • Json-server
      • 使用axios
  • Hooks

组件学习

创建组件

src目录下新建一个App.js文件,这个App.js就是我们创建的新的组件。

其实组件就是一个函数,所以我们只需要创建函数就能完成组件的创建。

在App.js文件中编写以下内容:

  1. 创建一个函数

    const 组件名 =()=>{return(<div>App组件</div>)
    }
    
  2. 导出组件

    export default 组件名
    
  3. 回到index.js文件,导入App组件文件路径

    import 组件名 from '文件路径'
    
  4. index.js文件中使用组件

    root.render(<div><组件库 /></div>
    );
    

组件的状态

状态(state):是可以让页面内容发生变化的数据。

使用方法:useState() 函数,如果需要修改状态就调用setCount(状态最新值)函数。

image-20240719161152619

const [count, setCount] = useState(默认值)

其中第一个元素是当前状态的值,第二个元素是更新该状态的函数。

我们来写一个计数器来更好得到理解state:

import { uesState } from 'react'const App =()=>{const [count, setCount] = uesState(10)return(<div><h1>计数器:{count} </h1><button onClick={()=> setCount(count+1)}>+1</button><button onClick={()=> setCount(count-1)}>-1</button></div>)
}
export default App

修改状态

规则:不要直接修改当前状态的值,应该创建新值。

注意:如果没有遵循该规则,会导致报错或组件无法重新渲染

如图:image-20240719165054282

在数组类型也是符合这种规则,如图:

image-20240719165151883

扩展:...list这个是表示之前的元素

setList([...list,‘新的内容'])
【案例】B站评论

我们要实现下图👇案例

image-20240719170323295

具体内容要求是有:

  1. 使用组件搭建结构
  2. 导航Tab的渲染和操作
  3. 评论列表的渲染和操作

安装Sass包

在这个项目当中我们需要使用到Sass更好的绘制样式形状,所以会用到Sass。如果你还不会Sass的话,可以跟我这之前的写过的一篇文章进行学习,相信你很快就能上手并熟练运用的💪⛽️

文章:一天搞定前端必备开发技能 (2)——less和Sass预处理器的使用_项目里嵌入 less 预处理器-CSDN博客

安装命令:

npm i sass

之后再src文件夹中创建一个app.scss文件用来编写sass样式。

之后我们在App.js文件导入scss文件和图片

导入图片

使用本地图片,需要手动导入。

❌不能像html一样直接在src导入图片路径

import 图片名称 from "图片路径"const App =()=>{return(//使用图片<img src={"图片名称"} alt="图片备注"></img>)
}
export default App

在这里我准备好了模版结构和样式给大家,大家直接复制粘贴到App.js文件当中即可;

🔗链接:B站评论案例笔记.md

注意⚠️:图片没有提供给大家,在代码中如果涉及到图片的请自行修改🌺。

组件结构搭建完成之后,我们就可以开始编写交互逻辑啦。

一共要实现以下👇三个功能:

  1. 根据状态渲染评论列表
//评论列表数据
const defaultList = [{//评论idrpid: 3,//用户信息user: {uid: "13258165",avatar: "https://未知信息",uname: "周杰伦",},//评论内容content: "哎哟,不错哦",//评论时间ctime: "10-1808:15",//喜欢数量like: 98,//0:未表态 1:喜欢 2:不喜欢action: 0,},];

使用useState来修改状态

const App=()=>{const[list,setList] = useState(defaultList)
}

列表渲染

<div classNaem="reply-list">{/*评论区*/}{list.map(item=>{return 列表项目})}
</div>
⚠️不要忘记了给每一个列表项添加key属性

image-20240719181606487

然后将这些评论编程动态的:

  • 评论头像image-20240719181651526

  • 评论名称image-20240719181711687

  • 评论事件image-20240719181751290

  • 喜欢数量image-20240719181822720

然后评论列表的渲染就基本完成了

  1. 删除评论

删除按钮的特性就是只有自己发表的评论才能够删除的,那么如何来实现呢?那就是使咱们登录用户的ID来索引判断是否是自己发表的评论。

{user.uid === item.user.uid &&() <span className="delete-bt">删除</span>)}

创建删除评论函数

//先给删除按钮绑定一个点击事件
onClick={onDelete(item.rpid))//删除评论
const onDelete=rpid=>{console.log(rpid)
}

最后用数组的过滤方法删除掉渲染

//删除评论
const onDelete=rpid=>{setList(list.filter(item=> item.rpid !== rpid))//如果要删除数组中的元素,需要调用 filter方法,并且一定要调用setList
}
  1. 喜欢和不喜欢

通过传入的action来判断是否是喜欢还是不喜欢。

image-20240719183954662

绑定点击事件

onClick={() =>onLike(item.rpid)}//创建一个喜欢的函数
const onLike=rpid=>{console.log(rpid)
}

高亮的效果显示其实就是一个取反的操作;喜欢的数量改变,还是一样先拿到action,如果是喜欢的话,就让item.like进行加减。

image-20240719184351543

不喜欢渲染也是一样的,这里我就不过多赘述啦!

image-20240719184457959

classNames优化

项目开发中,当多个类名都是动态的,手动处理会变得非常困难。

如果有多个类别都是动态的,那这个时候再来进行手动处理呢,会变得非常的困难,比如咱们来看一个例子,这边是我们经常用的一种类别处理的方式。但如果再有一个。也是动态的,你可能需要。再写一个三元表达式。3个第4个呢,再手动。那有没有更好的方式呢?

<button className={disabled ?'btnbtn-disabled':'btn'}></button>

今天我们就来学习使用classnames包来优化类名处理。

  1. 安装包

    npm i classnames
    
  2. 导包

    import classNames from 'classnames'
    

使用方法:

咱们直接上案例来进行学习

import classNames from 'classnames'
const App =()=>{// 是否禁用const [disabled,setDisabled] = useState(false)// 大小const [size,setSize] =useState('small')return(<div><button>按钮</button><hr/><div>操作:<button onClick={()=> setDisabled(true)}>禁用</button><button onClick={()=> setSize('small')}>变小</button><button onClick={()=> setSize('large')}>变大</button></div></div>)
}
export default App

以上👆就是我们会对这个按钮,给它来去加一些相应的样式,那并且这边,我还准备了两个状态,一个表示是否禁用一个。是按钮的大小,然后接下来呢,咱们还有分别有3个按钮进行控制。

  1. 如果类名一直都有的,就在函数参数内写好

    <button className={classNames('一直都用的class')}>按钮</button>
    
  2. 使用逻辑运算(适合处理单个类名)

    //语法模版
    <button className={className('一直都用的class',条件1 && ‘样式1’)}>按钮</button>
    
    //联系案例
    // 还需要联系上面的useState状态来判断const [disabled,setDisabled] = useState(false)<button className={classNames('btn',disabled && 'btn-disabled')}>按钮</button>
    

    这里classNames函数会根据disabled的值来决定是否添加'btn-disabled'这个类名。如果disabledtrueclassName将会是'btn btn-disabled';如果disabledfalseclassName将会是'btn'

  3. 使用对象语法(适合处理多个类名)

    //语法模版
    <button className={className('一直都用的class',{'样式1':条件1,'样式2':条件2,'样式3':条件3,
    })}>按钮</button>
    
    //联系案例// 是否禁用const [disabled,setDisabled] = useState(false)// 大小const [size,setSize] =useState('small')const [disabled,setDisabled] = useState(false)<button className={className('btn',{})}>按钮</button>
    

    注意⚠️:

    useState(false) 表示初始状态 disabled 的值被设置为 falsesetDisabled 是一个函数,你可以在组件中调用它来更新 disabled 的状态。所以,初始时 disabled 的取值是 false

完整代码:

import {useState} from 'react'
import classNames from 'classnames'
// import 'App.css'; // 导入CSS模块
const App =()=>{// 是否禁用const [disabled,setDisabled] = useState(false)// 大小const [size,setSize] =useState('small')return(<div><button className={classNames('btn',{'btn-disabled':disabled,'btn-small':size === 'small','btn-large':size === 'large',})}>按钮</button><hr/><div>操作:<button onClick={()=> setDisabled(true)}>禁用</button><button onClick={()=> setSize('small')}>变小</button><button onClick={()=> setSize('large')}>变大</button></div></div>)
}
export default App

状态操作表单元素

步骤:

  1. 准备一个状态

    cosnt [value,setValeue] = useState('')
    
  2. 实现数据到是视图的绑定,使用value值绑定状态值

  3. 实现视图到数据的绑定,使用onChange属性设置状态

    <input value={value} onChange={e => setValue(e.target.value)}
    
    • e.target:拿到dom对象
  4. 调用setValue()函数来更新状态

案例:绑定复选框

import { useState } from "react";const App = () => {const [checked, setChecked] = useState(false);return (<div><inputtype="checkbox"checked={checked}onChange={(e) => setChecked(e.target.checked)}/>{checked ? "选中了" : "未选中"}</div>);
};
export default App;

注意⚠️:valueonChange的值需要同时出现,不然没法实现绑定事件.

这种模式在React中有一个专业的术语:受控组件.所谓的受控组件就是收到React状态控制的表单元素.

useRef

在React组件中操作DOM,需要使用useRef,分为两步:

  1. 创建一个ref对象

    const 对象名 = useRef(null)
    
  2. 与JSX绑定

    <input ref={对象名}/>
    
  3. 根据业务进行DOM操作:通过对象名.current.DOM属性拿到DOM对象

案例:

import { useRef } from "react";const inputRef = useRef(null)<input ref={inputRef}/><button onClick={()=>alert(inputRef.current.value)}>获取文本框的值</button>

组件通讯

使用场景:一个组件需要使用另一个组件的数据。

根据组件之间的层级关系,常见的React组件通讯分为3种:

  1. 父子组件通讯
  2. 非父子组件通信
  3. 状态管理工具

父子组件通讯

父传子通讯

父组件提供数据,通过props传递给子组件使用。

作用:给组件传递数据,是React组件通讯的基础。

使用步骤:

  1. 传递props:在组件标签上添加属性

    <组件名 定义传递属性="属性值"/>
    
  2. 接受props:通过参数拿到

    const 组件名 = props =>{return(<标签 属性={props.定义传递属性}/>)
    }
    

案例:

const Study = props=>{return (<div style={{backgroundColor:'red' , width:props.w, height:props.h }}></div>)
}
//使用组件
const App = () => {
return (<div><Study w={100} h={200} />{/* <Study w={"100px"} h={"200px"} />  */}</div>);
};
export default App;

在React中,属性的传递方式有两种:字符串和JavaScript表达式。在上面的例子中,<Study w="100px" h="200px" /><Study w=100 h=200 /> 表现的行为是不同的:

  1. 字符串形式 (<Study w="100px" h="200px" />):
    • 这里的 wh 属性被传递为字符串。即使它们看起来像是数字后面跟着单位(例如 "100px"),它们在JavaScript中被当作字符串处理。
    • 这意味着在组件内部,props.wprops.h 将会是字符串类型的值,包含单位。
  2. JavaScript表达式形式 (<Study w=100 h=200 />):
    • 这里的 wh 属性直接作为JavaScript表达式传递,没有引号。这意味着它们将按照它们在JSX中声明的类型传递给组件。

在组件中如果期望 props.wprops.h 是带有单位的CSS尺寸值。最好还是在设置样式之前将数字转换为带有单位的字符串。

例如,在组件内部添加逻辑来添加单位:

const Study = props => {const width = `${props.w}px`; // 假设props.w是数字,这里添加了'px'单位const height = `${props.h}px`; // 同上return (<div style={{backgroundColor: 'red', width, height }}></div>);
};

在这个例子中,无论 props.wprops.h 是数字还是字符串,我们都确保它们被转换为带有单位的字符串,以便正确地应用CSS样式。

注意⚠️:这里运用到了模板字符串(也称为模板字面量)的语法。模板字符串允许你嵌入表达式到字符串字面量中,用${}包裹表达式,然后通过插值表达式的值。

简化props

我们还可以对props对象进行简化,由于props是一个对象,我们这里可以直接通过结构的方式直接拿到传过来的值。然后就能删掉props.

const Study = ({w,h})=>{return (<div style={{backgroundColor:'red' , width:w, height:h }}></div>)
}
//使用组件
const App = () => {
return (<div><Study w={100} h={200} /></div>);
};
export default App;

在实际开发中我们推荐使用简化方式,另外还可以在结构里面添加一个默认值。

const Study = ({w=10,h=20})=>{return (<div style={{backgroundColor:'red' , width:w, height:h }}></div>)
}
//使用组件
const App = () => {
return (<div><Study w={100} h={200} />对比,上面一个是修改了默认值,下面一个是直接默认值<Study/></div>);
};
export default App;

image-20240721125251552

子到父通讯

语法模版:

  1. 父组件准备修改数据的函数,传递给子部件

    //父组件
    const 修改数据函数名 = 参数=>{}
    <标签名 修改数据函数名={修改数据函数名}></标签名>	//将修改数据函数传递给子组件
    
  2. 子组件调用函数,将数据作为参数回到父组件

    //子组件
    const 组件名 =({参数,修改数据函数名})=>{return <标签名 onClick ={()=>修改数据函数名(值)}></标签名>
    }	//子组件调用函数
    

案例:

App.css文件:

.container {display: flex; /* 设置为Flex容器 */align-items: center; /* 垂直居中对齐 */
}
.yes { background-color: #c0e2f0;width: 100px;height: 30px;border: 1px solid black;margin:5px;text-align: center;
}
.no {background-color: #f6c8c8;
}

App.js文件:

import { useState } from "react";
import classNames from "classnames";
import "./App.css";
// 子组件
const Son = ({ id, num,change }) => {//子组件调用函数changereturn (<div className="container"><div className={classNames("yes", id && "no")}>{String(id)}</div><button onClick={() => change(num)}>点击按钮变换颜色</button>{/*change(id)将数据作为参数回到父组件 */}</div>);
};// 数据
const datas = [{num: 1,id: true,},{num: 2,id: true,},{num: 3,id: false,},
];// 父组件
const App = () => {const [data, setData] = useState(datas); //准备默认值const change = (num) => {//父组件准备修改数据的函数setData(data.map((item) => {if (item.num === num) {return {...item,id: !item.id,};}return item}));};return (<div>{data.map((item) => {return <Son key={item.num} num= {item.num} id={item.id} change={change} />;//遍历渲染 change={change}传递给子部件})}</div>);
};
export default App;

最后实现的案例效果:image-20240721180009982

我们还可以在遍历渲染的时候再次优化代码:

<div>{data.map((item) => {// return <Son key={item.num} num= {item.num} id={item.id} change={change} />;return <Son key={item.num} {...item} change={change} />;//{...item}表示数据中的其他属性分别传递给子组件})}</div>

非父子通讯

兄弟关系

根据组件之间的层级关系,常见的有两种情况:

image-20240721180627027

  1. 找到父组件,提供要共享的数据
  2. 通过父到子通讯,来展示好友名称
  3. 通过子到父通讯,来修改选中的好友

在React中有专门的一个术语来形容:状态提升
如果两个兄弟组件要通讯,就把共享数据提升到公共父组件中

后代关系

React的Context API提供了一种方式,允许你共享那些对于组件树中许多组件都必不可少的数据,例如用户偏好、地区设置、主题等,而不必通过每一层组件手动传递props。

Context(上下文):范围,无视组件层级关系,
跨组件通讯。

  1. 创建Context对象

    const 对象名 = createContext()
    
  2. 划定范围,提供共享数据

    <对象名.Provider value={共享数据}>父组件
    </对象名.Provider>
    
  3. 范围内的组件,获取共享数据

    const 共享数据 = useContext(对象名)
    

案例:共享消息

import React, { createContext, useState, useContext } from 'react';// 创建Context对象
const MessageContext = createContext();// 创建Provider组件
const MessageProvider = ({ children }) => {const [message, setMessage] = useState('Hello, World!');// 更新消息的函数const updateMessage = (newMessage) => {setMessage(newMessage);};return (<MessageContext.Provider value={{ message, updateMessage }}>{children}</MessageContext.Provider>);
};// 创建子组件
const MessageDisplay = () => {const { message, updateMessage } = useContext(MessageContext);return (<div><p>{message}</p><button onClick={() => updateMessage('New Message')}>Change Message</button></div>);
};// 创建另一个子组件
const AnotherComponent = () => {const { message } = useContext(MessageContext);return (<div><h2>Another Component</h2><p>Message from context: {message}</p></div>);
};// 应用的顶层组件
const App = () => {return (<MessageProvider><div><MessageDisplay /><AnotherComponent /></div></MessageProvider>);
};export default App;

代码解释:

  1. 创建Context: 使用 createContext 创建一个 MessageContext
  2. 创建Provider: MessageProvider 组件使用 useState 钩子来管理消息状态,并提供了一个 updateMessage 函数来更新消息。它通过 MessageContext.Provider 将这些值提供给子组件。
  3. 创建子组件:
    • MessageDisplay 组件使用 useContext 钩子从 MessageContext 获取消息和更新函数,并显示消息。它还提供了一个按钮来更改消息。
    • AnotherComponent 组件也使用 useContext 钩子从 MessageContext 获取消息,并显示它。
  4. 应用的顶层组件: App 组件使用 MessageProvider 来包裹 MessageDisplayAnotherComponent,确保它们可以访问到Context中的数据。

useEffet的使用

useEffect的作用:在组件生命周期的三个阶段(挂载更新卸载),执行网络请求、浏览器API等操作。这些操作,也叫:副作用😭。

语法:useEffect(Effect函数,依赖项数组)

  • Effect函数:副作用代码
  • 依赖项数组:控制Effect函数的执行时机(可选填)【一般在使用动态数据的时候使用,在更新时用的最多】

生命周期三个阶段:

  • 挂载时:

    useEfect(()=>{//挂载操作代码
    },[])
    
  • 更新时:

    useEffect(()=>{//更新操作代码
    },[依赖项数组])
    

    注意⚠️:更新时调用方式会在组件挂载以及更新时都会执行。

  • 卸载时:

    useEffect(()=>{return()=>{//卸载操作代码}
    },[])
    

    案例:计数器组件

    这个组件将展示一个计数器,每次点击按钮时计数器会增加。同时,组件会在挂载时打印一条消息,在更新时打印另一条消息,并在卸载时清理资源。

    import React, { useState, useEffect } from 'react';function Counter() {const [count, setCount] = useState(0);// 挂载时执行的副作用useEffect(() => {console.log('组件挂载');return () => {console.log('组件卸载');};}, []); // 空依赖项数组,仅在挂载时执行// 更新时执行的副作用useEffect(() => {console.log(`计数器更新为:${count}`);}, [count]); // 依赖项数组包含 count,每当 count 更新时执行return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);
    }export default Counter;
    

    代码解释:

    1. 状态初始化: 使用 useState 钩子初始化计数器状态 count
    2. 挂载时的副作用: 第一个 useEffect 没有依赖项数组,因此它只在组件挂载时执行一次。它在控制台中打印一条消息,并在组件卸载时执行返回的函数,打印另一条消息。
    3. 更新时的副作用: 第二个 useEffect 依赖于 count。每当 count 更新时,这个 useEffect 都会重新运行,并在控制台中打印新的计数器值。
    4. 渲染UI: 组件渲染一个段落和一个按钮。按钮的点击事件处理器会调用 setCount 函数,从而更新 count 状态。

    这个示例展示了 useEffect 如何在组件的不同生命周期阶段执行代码,以及如何通过依赖项数组控制副作用的执行。

useEffect扩展

推荐:一个useEffect负责一个完整功能

useEffect(()=>{//更新操作代码(这里直接用更新来代替挂载)return()=>{//卸载操作代码}
},[依赖项数组])

依赖项说明:什么样的数据才能说明是依赖项呢?

指定依赖项的原则:Effect函数中用到的,并且是可变的值。(例如:props/state/组件中创建的变量等)

以下是一个简单的例子,演示了如何使用 useEffect 来实现一个组件的挂载和卸载操作:

import React, { useState, useEffect } from 'react';function Clock() {// 组件状态,用于显示时间const [time, setTime] = useState(new Date().toLocaleTimeString());// 使用 useEffect 钩子来处理副作用useEffect(() => {// 定义一个更新时间的函数const updateTime = () => {setTime(new Date().toLocaleTimeString());};// 设置定时器,每秒更新时间const timer = setInterval(updateTime, 1000);// 这是 effect 的清理函数,会在组件卸载时执行return () => {clearInterval(timer);};}, []); // 空的依赖项数组意味着这个 effect 只在挂载时运行一次// 渲染时显示当前时间return (<div>The time is: {time}</div>);
}export default Clock;

在这个例子中:

  • Clock 组件显示当前的时间,并且每秒更新一次。
  • useState 钩子用于创建 time 状态变量,初始值为当前的本地时间字符串。
  • useEffect 钩子用于设置一个定时器,该定时器每秒调用 updateTime 函数来更新时间。
  • 定时器通过 setInterval 创建,并在 useEffect 的返回函数中清除,以确保在组件卸载时不会继续运行。
  • 依赖项数组是空的 [],这意味着 useEffect 只在组件挂载时运行一次,不会在更新时重新运行。

useEffect应用——发送请求

场景:组件初次渲染时,发送请求获取数据。

步骤:

  1. 调用useEffect,依赖项为空数组
  2. 创建新函数,在该函数上使用async并调用
  3. 发送请求,通过await获取到数据,然后使用
useEffect(()=>{const 函数名 = async()=>{await}函数名()	//调用函数
},[])

Json-server

使用json-server提供一个接口

image-20240721224015809

使用axios

安装命令

npm i axios
useEffect(()=>{const 函数名 = async()=>{const res = await axois get('接口地址')setState(res.data)	//更新到状态State里面}函数名()	//调用函数
},[])

Hooks

ReactHooks是以use开头的函数,比如,useState/useEffect/useContext等。

Hooks(钩子):为组件提供不同的React特性,比如,useStateHook为组件提供状态。

使用规则:只能在组件的顶层调用,不能嵌套在if、for、其他函数中。

原理:React组件依赖Hooks的调用顺序,必须保证所有Hooks,在每次渲染时,调用顺序一致。

image-20240721225454872

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

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

相关文章

学习笔记之Java篇(0726)

2、封装 1、封装的使用细节 2、开发中封装的简单规则&#xff1a; 属性一般使用private访问权限。 属性私有后&#xff0c;提供相应的get/set方法来访问相关属性&#xff0c;这些方法通常是public修饰后&#xff0c;以提供属性的赋值与读取操作&#xff08;注意&#xff1a;b…

情绪稳定的人有什么特点?

第一部分&#xff1a;至纯之人&#xff0c;大器晚成 1.1 单纯&#xff0c;不是天真 你知道吗&#xff1f;那些能够成就大事的人&#xff0c;往往在人性上非常单纯。他们对外界的需求很低&#xff0c;更多的是向内寻求。这样的人&#xff0c;他们的内心世界像一片净土&#xff…

二叉树 N0=N2+1

N0 叶子节点&#xff0c;度为 0 的节点&#xff1b; N1 度为 1 的节点&#xff1b; N2 度为 2 的节点 度为 0 的节点为&#xff1a;H、I、J、K、G 度为 1 的节点&#xff1a;E、F 度为 2 的节点&#xff1a;A、B、D、C N0 N2 1&#xff0c;即&#xff1a;度为 0 的叶子节点 …

力扣高频SQL 50 题(基础版)第四题

文章目录 力扣高频SQL 50 题&#xff08;基础版&#xff09;第四题584.寻找用户推荐人题目说明思路分析实现过程准备数据实现方式结果截图 力扣高频SQL 50 题&#xff08;基础版&#xff09;第四题 584.寻找用户推荐人 题目说明 表: Customer -------------------- | Colu…

虚拟机配置RabbitMQ集群教程

RabbitMQ是常用的一款消息中间件&#xff0c;那么如何在我们虚拟机中创建其集群呢&#xff1f;跟着博主这篇文章让你一步到位 本篇搭建的是三台机器为一个集群&#xff01;假设大家虚拟机都为初始化状态&#xff0c;从0开始&#xff08;注意集群搭建需要CentOS8以上环境&#x…

【五】MySql8基于m2芯片arm架构Ubuntu24虚拟机安装

文章目录 1. 更新系统包列表2. 安装 MySQL APT Repository3. 更新系统包列表4. 安装 MySQL Server5. 运行安全安装脚本6. 验证 MySQL 安装7. 配置远程连接7.1 首先要确认 MySQL 配置允许远程连接&#xff1a;7.2 重启 MySQL 服务&#xff1a;7.3 检查 MySQL 用户权限&#xff1…

详解数据结构之二叉树(二叉链,使用递归)

详解数据结构之二叉树(二叉链&#xff0c;使用递归实现) 二叉链 二叉链&#xff0c;二叉树的链式结构&#xff0c;其中数据域data存放节点的值&#xff0c;指针域left和right分别存放左孩子节点的地址、右孩子节点的地址。 typedef int BinaryTDataType; typedef struct Bin…

ChatGPT的原理和成本

ChatGPT就是人机交互的一个底层系统&#xff0c;某种程度上可以类比于操作系统。在这个操作系统上&#xff0c;人与AI之间的交互用的是人的语言&#xff0c;不再是冷冰冰的机器语言&#xff0c;或者高级机器语言&#xff0c;当然&#xff0c;在未来的十来年内&#xff0c;机器语…

K8S 部署peometheus + grafana 监控

安装说明 如果有下载不下来的docker镜像可以私信我免费下载。 系统版本为 Centos7.9 内核版本为 6.3.5-1.el7 K8S版本为 v1.26.14 动态存储&#xff1a;部署文档 GitHub地址 下载yaml 文件 ## 因为我的K8S 版本比较新&#xff0c;我下载的是当前的最新版本&#xff0c;你的要…

go语言day18 reflect反射

Golang-100-Days/Day16-20(Go语言基础进阶)/day19_Go语言反射.md at master rubyhan1314/Golang-100-Days (github.com) 7-19 接口&#xff1a;底层实现_哔哩哔哩_bilibili 一、interface接口 接口类型内部存储了一对pair(value,Type) type interface { type *Type // 类型信…

Linux:传输层(2) -- TCP协议(2)

目录 1. 流量控制 2. 滑动窗口 3. 拥塞控制 4. 延迟应答 5. 捎带应答 6. 面向字节流 7. 粘包问题 8. TCP异常情况 1. 流量控制 接收端处理数据的速度是有限的. 如果发送端发的太快 , 导致接收端的缓冲区被打满 , 这个时候如果发送端继续发送 , 就会造成丢包, 继而引…

7月24日JavaSE学习笔记

序列化版本控制 序列化&#xff1a;将内存对象转换成序列&#xff08;流&#xff09;的过程 反序列化&#xff1a;将对象序列读入程序&#xff0c;转换成对象的方式&#xff1b;反序列化的对象是一个新的对象。 serialVersionUID 是一个类的序列化版本号 private static fin…

dsp c6657 SYS/BIOS学习笔记

1 SYS/BIOS简介 SYS/BIOS是一种用于TI的DSP平台的嵌入式操作系统&#xff08;RTOS&#xff09;。 2 任务 2.1 任务调度 SYS/BIOS任务线程有0-31个优先级&#xff08;默认0-15&#xff0c;优先级0被空闲线程使用&#xff0c;任务最低优先级为1&#xff0c;最高优先级为15&am…

Java | Leetcode Java题解之第264题丑数II

题目&#xff1a; 题解&#xff1a; class Solution {public int nthUglyNumber(int n) {int[] dp new int[n 1];dp[1] 1;int p2 1, p3 1, p5 1;for (int i 2; i < n; i) {int num2 dp[p2] * 2, num3 dp[p3] * 3, num5 dp[p5] * 5;dp[i] Math.min(Math.min(num2…

昇思25天学习打卡营第20天|CV-ResNet50图像分类

打卡 目录 打卡 图像分类 ResNet网络介绍 数据集准备与加载 可视化部分数据集 残差网络构建 Building Block 结构 代码实现 Bottleneck结构 代码实现 构建ResNet50网络 代码定义 模型训练与评估 可视化模型预测 重点&#xff1a;通过网络层数加深&#xff0c;感知…

数据输入输出的概念

文章目录 数据输入输出的概念及在C语言中的实现简单的格式输入与输出用简单的printf函数输出数据用简单的scanf函数输入数据较复杂的输入输出格式控制输出数据格式控制 数据输入输出的概念及在C语言中的实现 数据的输入与输出是相对于计算机而言的。其中&#xff1a; 从计算机…

昇思25天学习打卡营第33天|共赴算力时代

文章目录 一、平台简介二、深度学习模型2.1 处理数据集2.2 模型训练2.3 加载模型 三、共赴算力时代 一、平台简介 昇思大模型平台&#xff0c;就像是AI学习者和开发者的超级基地&#xff0c;这里不仅提供丰富的项目、模型和大模型体验&#xff0c;还有一大堆经典数据集任你挑。…

BM58 字符串的排列

1.题目描述 输入一个长度为 n 字符串&#xff0c;打印出该字符串中字符的所有排列&#xff0c;你可以以任意顺序返回这个字符串数组。 例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。 数据范围&#xff1a;n<10n<10 要求&#…

本地搭建rtmp拉流

本地搭建rtmp拉流 可按照步骤来 关注公众号&#xff1a;城羽海 更多有趣实用教程 下载地址: 从微信公众号发送关键词 rtmp可获取下载地址 文章目录 本地搭建rtmp拉流 可按照步骤来 关注公众号&#xff1a;城羽海 更多有趣实用教程 拿到之后如图所下&#xff1f;二、配置obs文…

华为网络模拟器eNSP安装部署教程

eNSP是图形化网络仿真平台&#xff0c;该平台通过对真实网络设备的仿真模拟&#xff0c;帮助广大ICT从业者和客户快速熟悉华为数通系列产品&#xff0c;了解并掌握相关产品的操作和配置、提升对企业ICT网络的规划、建设、运维能力&#xff0c;从而帮助企业构建更高效&#xff0…