一天搞定React(3)——Hoots组件

news2024/9/20 9:12:59

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

文章目录

  • 组件学习
    • 创建组件
    • 组件的状态
      • 修改状态
        • 【案例】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 = [
    {
      //评论id
      rpid: 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>
      <input
        type="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 }) => {
  //子组件调用函数change
  return (
    <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.coloradmin.cn/o/1940735.html

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

相关文章

【Node】npm i --legacy-peer-deps,解决依赖冲突问题

文章目录 &#x1f356; 前言&#x1f3b6; 一、问题描述✨二、代码展示&#x1f3c0;三、运行结果&#x1f3c6;四、知识点提示 &#x1f356; 前言 npm i --legacy-peer-deps&#xff0c;解决依赖冲突问题 &#x1f3b6; 一、问题描述 node执行安装指令时出现报错&#xff…

【QT】label适应图片(QImage)大小;图片适应label大小

目录 0.简介 1.详细代码 1&#xff09;label适应img大小 2&#xff09;img适应label大小 0.简介 一个小demo &#xff0c;想在QLabel中放一张QImage的图片&#xff0c;我有一张图片叫【bird.jpg】&#xff0c;是提前放在资源文件中的&#xff0c;直接显示在label上后&#…

【网络】网络聊天室udp

网络聊天室udp 一、低耦合度代码1、代码2、测试结果 二、高耦合度代码1、服务端小改&#xff08;1&#xff09;维护一个unordered_map用户列表&#xff08;2&#xff09;服务端代码&#xff08;3&#xff09;客户端不改的情况下结果展示 2、大改客户端&#xff08;udp全双工用多…

通过QT进行服务器和客户端之间的网络通信

客户端 client.pro #------------------------------------------------- # # Project created by QtCreator 2024-07-02T14:11:20 # #-------------------------------------------------QT core gui network #网络通信greaterThan(QT_MAJOR_VERSION, 4): QT widg…

饥荒dst联机服务器搭建基于Ubuntu

目录 一、服务器配置选择 二、项目 1、下载到服务器 2、解压 3、环境 4、启动面板 一、服务器配置选择 首先服务器配置需要2核心4G&#xff0c;4G内存森林加洞穴大概就占75% 之后进行服务器端口的开放&#xff1a; tcp:8082 tcp:8080 UDP:10888 UDP:10998 UDP:10999 共…

套接字编程一(简单的UDP网络程序)

文章目录 一、 理解源IP地址和目的IP地址二、 认识端口号1. 理解 "端口号" 和 "进程ID"2. 理解源端口号和目的端口号 三、 认识协议1. 认识TCP协议2. 认识UDP协议 四、 网络字节序五、 socket编程接口1. socket 常见API2. sockaddr结构&#xff08;1&#…

输入设备应用编程-I.MX6U嵌入式Linux C应用编程学习笔记基于正点原子阿尔法开发板

输入设备应用编程 输入类设备编程介绍 什么是输入设备 输入设备&#xff08;input 设备&#xff09;&#xff0c;如鼠标、键盘、触摸屏等&#xff0c;允许用户与系统交互 input 子系统 Linux系统通过input子系统管理多种输入设备 Input子系统提供统一的框架和接口&#xff…

网络编程之LINUX信号

注意发送信号是给进程&#xff0c;不是线程&#xff0c;调用的是KILL函数&#xff0c;SIG是信号种类。pid0是本进程的其他的进程。 可以通过设置ERRNO来查看返回的错误&#xff0c;如下&#xff1a; 当目标进程收到信号后&#xff0c;要对信号进行一些执行操作&#xff1a; 定义…

[每周一更]-(第106期):DNS和SSL协作模式

文章目录 什么是DNS&#xff1f;DNS解析过程DNS解析的底层逻辑 什么是SSL&#xff1f;SSL证书SSL握手过程SSL的底层逻辑 DNS与SSL的协同工作过程 什么是DNS&#xff1f; DNS&#xff08;Domain Name System&#xff0c;域名系统&#xff09;是互联网的重要组成部分&#xff0c…

黑马程序员MySQL基础学习,精细点复习【持续更新】

文章目录 数据库Mysql基础一、数据库1.数据库2.数据库管理系统3.SQL4.Mysql目录结构5.关系型数据库6.SQL基础概念 mysql高级一、数据库备份和还原1.图形化界面备份与还原 二、约束1.分类&#xff1a;2.主键约束3.唯一约束4.非空约束5.默认值约束6.外键约束 三、表关系1.概述2.一…

《Windows API每日一练》13.1 打印基础

在Windows中使用打印机时&#xff0c;在调用一系列与打印相关的GDI绘图函数的背后&#xff0c;实际上启动了一系列模块之间复杂的交互过程&#xff0c;包括 GDI32库模块、打印机设备驱动程序库模块&#xff08;带.DRV后缀的文件&#xff09;、Windows后台打印处理程序&#xff…

5. harbor镜像仓库

harbor镜像仓库 一、镜像仓库1、类型2、构建私有仓库的方案 二、部署harbor仓库(单机版)1、安装docker(略)2、安装docker-compose工具3、安装harbor4、生成harbor需要的证书、密钥(V3版本证书)4.1 创建CA4.2 创建harbor仓库需要的证书 5、编辑harbor配置文件6、启动harbor 三、…

【C++】17.AVL树

一、AVL树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查找元素相当于在顺序表中搜索元素&#xff0c;效率低下。因此&#xff0c;两位俄罗斯的数学家G.M.Adelson-Velskii和E.M.Landis在1962年发明了一种…

Linux实用操作二

文章目录 Linux实用操作二日期、时区&#xff1a;date命令查看日期时间作用&#xff1a;语法&#xff1a;字段解释&#xff1a;操作&#xff1a; 修改Linux系统时区作用&#xff1a;操作&#xff1a; 使用ntp进行时间同步和校准作用&#xff1a;操作&#xff1a; IP地址、主机名…

buuctf web 第五到八题

[ACTF2020 新生赛]Exec 这里属实有点没想到了&#xff0c;以为要弹shell&#xff0c;结果不用 127.0.0.1;ls /PING 127.0.0.1 (127.0.0.1): 56 data bytes bin dev etc flag home lib media mnt opt proc root run sbin srv sys tmp usr var127.0.0.1;tac /f*[GXYCTF2019]Pin…

【数学建模】多波束测线问题(持续更新)

多波束测线问题 问题 1建立模型覆盖宽度海水深度重叠长度重叠率 问题二问题三问题四 问题 1 与测线方向垂直的平面和海底坡面的交线构成一条与水平面夹角为 α \alpha α的斜线&#xff08;如下图&#xff09;&#xff0c;称 α \alpha α为坡度。请建立多波束测深的覆盖宽度及…

世界华人国学泰斗级人物颜廷利:人类史上全球公认最伟大的思想家

世界华人国学泰斗级人物颜廷利:人类史上全球公认最伟大的思想家 颜廷利教授,一位在21世纪东方哲学、科学界具有深远影响力的人物,同时也是当代中国教育界的知名教授、周易起名与易经姓名学的专家,以及现代国学的杰出代表。他在其著作《升命学说》中提出了一系列独到的理论,包括…

Mybatis--分页查询

一、分页查询 分页查询则是在页面上将本来很多的数据分段显示&#xff0c;每页显示用户自定义的行数。可提高用户体验度&#xff0c;同时减少一次性加载&#xff0c;内存溢出风险。 1、真假分页 分页分为&#xff1a;真分页和假分页。 假分页&#xff1a;一次性查询所有数据存入…

笔记小结:卷积神经网络之多输入多输出通道

本文为李沐老师《动手学深度学习》笔记小结&#xff0c;用于个人复习并记录学习历程&#xff0c;适用于初学者 彩色图像具有标准的RGB通道来代表红、绿和蓝&#xff0c;需要三个通道表示&#xff0c;故而只有单输入单输出是不够的。 对于单个输入和单个输出通道的简化例子&…

Yolo-World网络模型结构及原理分析(一)——YOLO检测器

文章目录 概要一、整体架构分析二、详细结构分析YOLO检测器1. Backbone2. Head3.各模块的过程和作用Conv卷积模块C2F模块BottleNeck模块SPPF模块Upsampling模块Concat模块 概要 尽管YOLO&#xff08;You Only Look Once&#xff09;系列的对象检测器在效率和实用性方面表现出色…