React基础语法

1.React介绍

React由Meta公司开发,是一个用于构建Web和原生交互界面的库

1.1 React优势

相较于传统基于DOM开发的优势

1.组件化的开发方式

2.不错的性能

相较于其他前端框架的优势

1.丰富的生态

2.跨平台支持

1.2React的时长情况

全球最流行,大厂必备

2.开发环境创建

create-react-app是一个快速创建React开发环境的工具,底层由Webpack构件,封装了配置细节,开箱即用执行命令:

npx create-react-app react-basic

cd react-basic
npm start

创建项目更多方式:

https://zh-hans.react.dev/learn/start-a-new-react-project

3.JSX基础

3.1什么是JSX

JSX是JavaScript和XML(HTML)的缩写,表示在JS代码中编写HTML模板结构,是React构建UI的方式

const message = 'this is message'function App() {return (<div className="App"><h1>My First React App</h1>{message}</div>);
}export default App;

3.2 JSX的本质

JSX并不是标准的JS语法,它是 JS的语法扩展,浏览器本身不能识别,需要通过解析工具做解析之后才能在浏览器中使用

3.3JSX高频场景-JS表达式

在JSX中可以通过 <font style="color:rgb(119, 119, 119);background-color:rgb(248, 248, 248);">大括号语法{}</font> 识别JavaScript中的表达式,比如常见的变量、函数调用、方法调用等等

使用引号传递字符串、JS变量、函数调用和方法调用、对象

注意:不能使用条件语句

const message = 'this is message'function getAge(){return 18
}function App() {return (<div className="App"><h1>My First React App</h1>{message}{/*函数调用*/}{getAge()}</div>);
}export default App;

3.4JS高频场景-列表场景

const list = [{id:1001, name:'Vue'},{id:1002, name: 'React'},{id:1003, name: 'Angular'}
]function App(){return (<ul>{list.map(item => <li key={item.id}>{item.name}</li>)}</ul>);
}export default App;

3.5JS高频场景-条件渲染

在React中,可以通过逻辑与运算&&、三元表达式(?:)实现基础的条件渲染

const flag = true;
const loading = true;function App() {return (<>{flag && <span>this is span</span>}{loading ? <span>loading...</span>:<span>this is span</span>}</>)
}export default App;

3.6JSX高频场景-复杂条件渲染

需求:列表中需要根据文章的状态适配

const type = 0; // 0 1 3function getArticleJSX() {if (type === 0) {return <div>无图模式</div>} else if (type === 1) {return <div>单图模式</div>} else if(type === 3){return <div>多图模式</div>}
}function App() {return (<>{getArticleJSX()}</>)
}export default App;

4.React的事件绑定

4.1基础实现

React中的事件绑定,通过语法on + 事件名称 = {事件处理程序}。整体上遵循驼峰命名

function App() {const clickHandle = () =>{console.log('button按钮点击了');}return (<button onClick={clickHandle}>click me</button>)
}export default App;

4.2使用事件参数

在事件回调函数中设置形参e即可

function App() {const clickHandle = (e) =>{console.log('button按钮点击了', e);}return (<button onClick={clickHandle}>click me</button>)
}export default App;

4.3传递自定义参数

语法:事件绑定的位置改造成箭头函数的写法,再执行clickHandler实际处理业务函数的时候传递实参

function App() {const clickHandle = (name) =>{console.log('button按钮点击了', name);}return (<button onClick={()=>clickHandle('jack')}>click me</button>)
}export default App;

注意:不能直接写函数调用,这里事件绑定需要一个函数引用

4.4同时传递事件对象的自定义参数

语法:在事件绑定位置传递事件实参e的自定义参数,clickHandle中声明形参,注意顺序对应

function App() {const clickHandle = (name, e) =>{console.log('button按钮点击了', name, e);}return (<button onClick={(e)=>clickHandle('jack', e)}>click me</button>)
}export default App;

5.React组件基础使用

5.1 组件是什么

概念:一个组件就是一个用户界面的一部分,它可以有自己的逻辑和外观,组件之间可以互相嵌套,也可以服用多次

5.2组件基础使用

在React中,一个组件就是首字母大写的函数,内部存放了组件的逻辑和视图UI,渲染增加只需要把组件当作标签书写即可

function Button() {return <button>click me</button>
}
function App() {return (<div><Button/><Button></Button></div>)
}export default App;

6.组件状态管理-useStatue

6.1基础使用

useState是一个React Hook(函数),它允许我们向组件添加一个状态变量,从而控制影响组件的渲染结果和普通的JS变量不同的是,状态变量一旦发生变化组件的视图UI也会跟着发生变化(数据驱动试图)

import React from "react";function App() {const [count, setCount] = React.useState(0)return (<div><button onClick={()=>setCount(count + 1)}>{count}</button></div>)
}export default App;

6.2状态的修改规则

在React中状态被认为是只读的,我们应该始终替换它而不是修改它,直接修改状态不能引发视图更新

6.3修改对象状态

对于对象类型的状态变量,应该始终给set方法一个全新的对象来进行修改

import React from "react";function App() {const [form, setForm] = React.useState({name : 'jack'})const handleChageName=() => {setForm({...form,name : 'john'})}return (<div><button onClick={()=>handleChageName()}>{form.name}</button></div>)
}export default App;

7.组建的基础样式处理

React组件基础的样式控制有两种方式,行内样式和class类名控制

import React from "react";function App() {return (<div><div style={{color:'red'}}> this is div</div></div>)
}export default App;

index.css

.foo{color: red;
}

App.js

import './index.css';function App() {return (<div><div className="foo"> this is div</div></div>)
}export default App;

8.B站评论案例

  1. 渲染评论列表
  2. 删除评论实现
  3. 渲染导航Tab和高亮实现
  4. 评论列表排序功能实现

8.1基础项目

App.js

import './App.scss'
import avatar from './images/bozai.png'/*** 评论列表的渲染和操作** 1. 根据状态渲染评论列表* 2. 删除评论*/// 评论列表数据
const defaultList = [{// 评论idrpid: 3,// 用户信息user: {uid: '13258165',avatar: '',uname: '周杰伦',},// 评论内容content: '哎哟,不错哦',// 评论时间ctime: '10-18 08:15',like: 88,},{rpid: 2,user: {uid: '36080105',avatar: '',uname: '许嵩',},content: '我寻你千百度 日出到迟暮',ctime: '11-13 11:29',like: 88,},{rpid: 1,user: {uid: '30009257',avatar,uname: '黑马前端',},content: '学前端就来黑马',ctime: '10-19 09:00',like: 66,},
]
// 当前登录用户信息
const user = {// 用户iduid: '30009257',// 用户头像avatar,// 用户昵称uname: '黑马前端',
}/*** 导航 Tab 的渲染和操作** 1. 渲染导航 Tab 和高亮* 2. 评论列表排序*  最热 => 喜欢数量降序*  最新 => 创建时间降序*/// 导航 Tab 数组
const tabs = [{ type: 'hot', text: '最热' },{ type: 'time', text: '最新' },
]const App = () => {return (<div className="app">{/* 导航 Tab */}<div className="reply-navigation"><ul className="nav-bar"><li className="nav-title"><span className="nav-title-text">评论</span>{/* 评论数量 */}<span className="total-reply">{10}</span></li><li className="nav-sort">{/* 高亮类名: active */}<span className='nav-item'>最新</span><span className='nav-item'>最热</span></li></ul></div><div className="reply-wrap">{/* 发表评论 */}<div className="box-normal">{/* 当前用户头像 */}<div className="reply-box-avatar"><div className="bili-avatar"><img className="bili-avatar-img" src={avatar} alt="用户头像" /></div></div><div className="reply-box-wrap">{/* 评论框 */}<textareaclassName="reply-box-textarea"placeholder="发一条友善的评论"/>{/* 发布按钮 */}<div className="reply-box-send"><div className="send-text">发布</div></div></div></div>{/* 评论列表 */}<div className="reply-list">{/* 评论项 */}<div className="reply-item">{/* 头像 */}<div className="root-reply-avatar"><div className="bili-avatar"><imgclassName="bili-avatar-img"alt=""/></div></div><div className="content-wrap">{/* 用户名 */}<div className="user-info"><div className="user-name">jack</div></div>{/* 评论内容 */}<div className="root-reply"><span className="reply-content">这是一条评论回复</span><div className="reply-info">{/* 评论时间 */}<span className="reply-time">{'2023-11-11'}</span>{/* 评论数量 */}<span className="reply-time">点赞数:{100}</span><span className="delete-btn">删除</span></div></div></div></div></div></div></div>)
}export default App

App.scss

.app {width: 80%;margin: 50px auto;
}.reply-navigation {margin-bottom: 22px;.nav-bar {display: flex;align-items: center;margin: 0;padding: 0;list-style: none;.nav-title {display: flex;align-items: center;width: 114px;font-size: 20px;.nav-title-text {color: #18191c;font-weight: 500;}.total-reply {margin: 0 36px 0 6px;color: #9499a0;font-weight: normal;font-size: 13px;}}.nav-sort {display: flex;align-items: center;color: #9499a0;font-size: 13px;.nav-item {cursor: pointer;&:hover {color: #00aeec;}&:last-child::after {display: none;}&::after {content: ' ';display: inline-block;height: 10px;width: 1px;margin: -1px 12px;background-color: #9499a0;}}.nav-item.active {color: #18191c;}}}
}.reply-wrap {position: relative;
}
.box-normal {display: flex;transition: 0.2s;.reply-box-avatar {display: flex;align-items: center;justify-content: center;width: 80px;height: 50px;}.reply-box-wrap {display: flex;position: relative;flex: 1;.reply-box-textarea {width: 100%;height: 50px;padding: 5px 10px;box-sizing: border-box;color: #181931;font-family: inherit;line-height: 38px;background-color: #f1f2f3;border: 1px solid #f1f2f3;border-radius: 6px;outline: none;resize: none;transition: 0.2s;&::placeholder {color: #9499a0;font-size: 12px;}&:focus {height: 60px;background-color: #fff;border-color: #c9ccd0;}}}.reply-box-send {position: relative;display: flex;flex-basis: 86px;align-items: center;justify-content: center;margin-left: 10px;border-radius: 4px;cursor: pointer;transition: 0.2s;& .send-text {position: absolute;z-index: 1;color: #fff;font-size: 16px;}&::after {position: absolute;width: 100%;height: 100%;background-color: #00aeec;border-radius: 4px;opacity: 0.5;content: '';}&:hover::after {opacity: 1;}}
}
.bili-avatar {position: relative;display: block;width: 48px;height: 48px;margin: 0;padding: 0;border-radius: 50%;
}
.bili-avatar-img {position: absolute;top: 50%;left: 50%;display: block;width: 48px;height: 48px;object-fit: cover;border: none;border-radius: 50%;image-rendering: -webkit-optimize-contrast;transform: translate(-50%, -50%);
}// 评论列表
.reply-list {margin-top: 14px;
}
.reply-item {padding: 22px 0 0 80px;.root-reply-avatar {position: absolute;left: 0;display: flex;justify-content: center;width: 80px;cursor: pointer;}.content-wrap {position: relative;flex: 1;&::after {content: ' ';display: block;height: 1px;width: 100%;margin-top: 14px;background-color: #e3e5e7;}.user-info {display: flex;align-items: center;margin-bottom: 4px;.user-name {height: 30px;margin-right: 5px;color: #61666d;font-size: 13px;line-height: 30px;cursor: pointer;}}.root-reply {position: relative;padding: 2px 0;color: #181931;font-size: 15px;line-height: 24px;.reply-info {position: relative;display: flex;align-items: center;margin-top: 2px;color: #9499a0;font-size: 13px;.reply-time {width: 86px;margin-right: 20px;}.reply-like {display: flex;align-items: center;margin-right: 19px;.like-icon {width: 14px;height: 14px;margin-right: 5px;color: #9499a0;background-position: -153px -25px;&:hover {background-position: -218px -25px;}}.like-icon.liked {background-position: -154px -89px;}}.reply-dislike {display: flex;align-items: center;margin-right: 19px;.dislike-icon {width: 16px;height: 16px;background-position: -153px -153px;&:hover {background-position: -217px -153px;}}.dislike-icon.disliked {background-position: -154px -217px;}}.delete-btn {cursor: pointer;&:hover {color: #00aeec;}}}}}
}.reply-none {height: 64px;margin-bottom: 80px;color: #99a2aa;font-size: 13px;line-height: 64px;text-align: center;
}

8.2完成版本

8.2.1列表渲染

{/* 评论项 */}{list.map((item) => (<div key={item.user.uid} className="reply-item">{/* 头像 */}<div className="root-reply-avatar"><div className="bili-avatar"><imgclassName="bili-avatar-img"alt=""/></div></div><div className="content-wrap">{/* 用户名 */}<div className="user-info"><div className="user-name">{item.user.uname}</div></div>{/* 评论内容 */}<div className="root-reply"><span className="reply-content">{item.content}</span><div className="reply-info">{/* 评论时间 */}<span className="reply-time">{item.ctime}</span>{/* 评论数量 */}<span className="reply-time">点赞数:{item.like}</span><span className="delete-btn" onClick={()=>deleteItem(item.rpid)}>
删除
</span></div></div></div></div>))

8.2.2 删除评论

 const [list, setList] = useState(defaultList)const deleteItem = (rpid) => {setList(list.filter(item => item.rpid !== rpid));}

8.3.2渲染导航Tab和高亮显示

 <li className="nav-sort">{/* 高亮类名: active */}{tabs.map((tab) => (<spankey={tab.type}className={`nav-item ${tab.type === activeTabType ? 'active' : ''}`}onClick={() => tabChange(tab.type)}>{tab.text}</span>))}{/*<span className='nav-item' onClick={()=>tabChange('time')}>最热</span>*/}</li>
 const [activeTabType, setActiveTabType] = useState(tabs[0].type); // 初始激活第一个 tabconst tabChange = (type) => {setActiveTabType(type);};

8.3.4评论列表排序

安装lodash库

npm install lodash
const [list, setList] = useState(defaultList)
useEffect(() => {// 根据点赞数量排序(热度排序)const sortedComments = _.orderBy(list, 'like', 'desc')setList(sortedComments);
}, []); // 空依赖数组表示这个 effect 只在组件挂载和卸载时运行一次
const deleteItem = (rpid) => {setList(list.filter(item => item.rpid !== rpid));
}
const [activeTabType, setActiveTabType] = useState(tabs[0].type); // 初始激活第一个 tabconst tabChange = (type) => {setActiveTabType(type);if (type === 'hot') {setList(_.orderBy(list, 'like', 'desc'));} else if (type === 'time') {setList(_.orderBy(list, 'ctime', 'asc'));}
};

8.3.5 样式书写优化

npm install classnames 
className={classNames('nav-item', {active: tab.type === activeTabType})}

9.React表单控制

9.1受控绑定

概念:使用React组件的状态(useState)控制表单状态

import {useState} from "react";function App() {const [value, setValue] = useState('');return (<input type="text"value={value}onChange={(e) => setValue(e.target.value)}></input>);
}export default App;

9.2非受控绑定

概念:通过DOM的方式获取表单的输入数据

import {useRef} from "react";function App() {var inputRef = useRef(null);const onChange = () => {console.log(inputRef.current.value)}return (<input type="text"ref={inputRef}onChange={onChange}></input>);
}export default App;

10.案例-B站评论案例

1.输入评论内容,并发布评论

1)进行表单受控绑定

<div className="reply-box-wrap">{/* 评论框 */}<textareaclassName="reply-box-textarea"placeholder="发一条友善的评论"value = {textValue}onChange={(e)=>setTextValue(e.target.value)}/>{/* 发布按钮 */}<div className="reply-box-send"><div className="send-text" onClick={()=>sendComment(textValue)}>发布</div></div>
</div>

2)点击“发布”触发发布评论

const [textValue, setTextValue] = useState('');
const sendComment = () => {setList([...list,{// 评论idrpid: 3,// 用户信息user: user,// 评论内容content: textValue,// 评论时间ctime: new Date().toLocaleString(),like: 88,}])setTextValue('');}

3)非受控绑定输入框

<div className="reply-box-wrap">{/* 评论框 */}<textareaclassName="reply-box-textarea"placeholder="发一条友善的评论"value = {textValue}ref={inputRef}onChange={(e)=>setTextValue(e.target.value)}/>{/* 发布按钮 */}<div className="reply-box-send"><div className="send-text" onClick={()=>sendComment(textValue)}>发布</div></div>
</div>

4)光标聚焦

const sendComment = () => {setList([...list,{// 评论idrpid: 3,// 用户信息user: user,// 评论内容content: textValue,// 评论时间ctime: new Date().toLocaleString(),like: 88,}])setTextValue('');inputRef.current.focus();}

2.id处理和时间处理(uuid和day.js)

npm install dayjs --save
npm install uuid --save

具体代码实现

const sendComment = () => {setList([...list,{// 评论idrpid: uuidV4(),// 用户信息user: user,// 评论内容content: textValue,// 评论时间ctime: dayjs(new Date()).format('MM-DD hh:mm'),like: 88,}])setTextValue('');inputRef.current.focus();}

11.React组件通信

概念:组件通信就是组件之间的数据传递,根据组件嵌套关系的不同,有不同的通信手段和方法

  1. A-B 父子通信
  2. B-C 兄弟通信
  3. A-E 跨层通信

11.1 父子通信-父传子

11.1.1 基础实现

实现步骤:

1.父组件传递数据-在子组件标签上绑定属性

2.子组件接收数据-子组件通过props参数接受数据

function Son(props) {return (<div>{props.name}</div>)
}function App() {const  name = 'react'return (<div><Son name={name} /></div>);
}export default App;

11.1.2props说明

props可以传递任意的合法数据,比如数字、字符串、布尔值、数组、对象、函数、JSX

props是只读对象

子组件只能读取props中的数据,不能直接进行修改,父组件的数据只能由父组件修改

11.1.3特殊的prop-chilren

场景:当我们把内容嵌套在组件的标签内部时,组件会自动在名为children的prop属性中接受该内容

function Son(props) {return <div>{props.children}</div>
}
function App() {const  name = 'react'return (<Son><span>this is span</span></Son>);
}export default App;

11.2 父子通信-子传父

核心思想:子组件中调用父组件中的参数并传递函数

function Son({ onGetMsg}) {const msg = "this is son msg";return (<div><button onClick={() => onGetMsg(msg)}>send</button></div>)
}
function App() {const getMsg = (msg) => {console.log(msg)}return (<div><Son onGetMsg={getMsg}></Son></div>);
}export default App;

11.3兄弟组件通信

实现思路:

借助状态提升机制,通过共同的父组件进行相抵之间的数据传递

import {useState} from "react";function A({onGetAName}) {const mag = "this is A name";return (<div>this is A,<button onClick={() => onGetAName(mag)}>send</button></div>);
}function B({name}) {return <div>this is B,{name}</div>
}function App() {const [name, setName] = useState("");const getAName = (name) => {setName(name);}return (<div><A onGetAName={getAName}></A><B name={name}></B></div>);
}export default App;

11.4 跨层组件通信

实现步骤:

1.使用createContext方法创建一个上下文对象Ctx

2.在顶层组件{App}中通过Ctx.Provider组件提供数据

3.在底层组件{B}中通过useContext钩子函数获取消费消息

import {createContext, useContext} from "react";var MsgContext = createContext();function A() {const msg = "this is A Component";return (<div>{msg}.<B/></div>);
}function B() {const msg = useContext(MsgContext);return <div>this is B,{msg}</div>
}function App() {const msg = "this is App Component";return (<div><MsgContext.Provider value={msg}><A/></MsgContext.Provider></div>);
}export default App;

12.React副作用管理-useEffect

12.1概念理解

useEffect是一个React Hook函数,用于在React组件中创建不是由时间引起而是由渲染本身引起的操作(副作用),比如发送AJAX请求,更改DOM等等

说明:上面的组件中没有发生任何的用户事件,组件渲染完毕之后就需要跟服务器要数据,整个过程属于“只渲染引起的操作”

12.2基础使用

需求:在组建渲染完毕之后,立刻从服务器端获取数据并展示在页面中

useEffect(() => { }, [])

说明:

  1. 参数1是一个函数,可以把它叫做副作用函数,在函数内部可以放置要执行的操作
  2. 参数2是一个数组(可选参),在数组里放置依赖项,不同依赖项会影响第一个参数函数的执行,当是一个空数组的时候,副作用函数只会在组件渲染完毕之后执行一次

接口地址:http://geek.itheima.net/v1_0/channels

1)安装axios

npm install axios 

2)发送请求

const [list, setList] = useState([]);
useEffect(() => {const getData = async () => {const res = await axios.get("http://geek.itheima.net/v1_0/channels");console.log(res.data.data.channels)setList(res.data.data.channels)}getData();}, []);

3)展示数据

import axios from "axios";
import {useEffect, useState} from "react";function App() {const [list, setList] = useState([]);useEffect(() => {const getData = async () => {const res = await axios.get("http://geek.itheima.net/v1_0/channels");console.log(res.data.data.channels)setList(res.data.data.channels)}getData();}, []);return (<div><ul>{list.map(item => <li key={item.id}>{item.name}</li>)}</ul></div>);
}export default App;

12.3useEffect依赖说明

useEffect副作用函数执行时机存在多种情况,根据传入依赖项的不同,会有不同的执行表现

依赖项副作用功函数的执行时机
没有依赖项组件初始渲染 + 组件更新时执行
空数组依赖只在初始渲染时执行一次
添加特定依赖项组件初始渲染 + 依赖项变化时执行

12.4清除副作用

概念:在useEffect中编写的由渲染本身引起的对接组件外部的操作,社区也经常把它叫做副作用函数,比如在useEffect中开启一个定时器,在组件卸载时把这个定时器清除掉,这个过程就是清楚副作用。

useEffect(()=>{return ()=>{// 清除副作用}
},[])

说明:清除副作用函数最常见的执行时机是在组件卸载时自动执行

import {useEffect, useState} from "react";function Son() {useEffect(() => {const timer = setInterval(() => {console.log("我是子组件的定时器")}, 1000)return () => {clearInterval(timer)console.log("子组件的定时器被销毁了")}}, []);return (<div>我是子组件</div>)
}function App() {const [show, setShow] = useState(true)return (<div>{show && <Son/>}<button onClick={() => setShow(false)}>卸载组件</button></div>);
}export default App;

13.自定义Hook

13.1自定义Hook实现

概念:自定义Hook是以use大头的函数,通过自定义Hook函数可以用来实现逻辑的封装和复用

封装自定义hook通用思路:

1.声明一个以use打头的函数

2.在函数体内封装可复用的逻辑(只要是可复用的逻辑)

3.把组件中用到的状态或者回调return出去(以对象或者数组)

4.在哪个组件中要用这个逻辑,就执行这个函数,结构出来状态和回调进行使用

import {useState} from "react";function useToggle() {const [value, setValue] = useState(true);const toggle = () => setValue(!value);return {value, toggle};
}function App() {const {value, toggle} = useToggle();return (<div>{value && <div>this is div</div>}<button onClick={toggle}>toggle</button></div>);
}export default App;

13.2React Hooks使用规则

1.只能在组件或者其他自定义Hook函数中调用

2.只能在组件的顶层调用,不能嵌套在if、for、其它函数中

14.案例-优化B站评论案例

14.1使用接口的方式获取评论列表并渲染

1)使用json-server工具模拟接口服务,通过axios发送请求

下载json-server到当前项目

npm i json-server -D

在项目文件夹下创建db.json文件

{"list": [{"rpid": 3,"user": {"uid": "13258165","avatar": "http://toutiao.itheima.net/resources/images/98.jpg","uname": "周杰伦"},"content": "哎哟,不错哦","ctime": "10-18 08: 15","like": 126},{"rpid": 2,"user": {"uid": "36080105","avatar": "http://toutiao.itheima.net/resources/images/98.jpg","uname": "许嵩"},"content": "我寻你千百度 日出到迟暮","ctime": "11-13 11: 29","like": 88},{"rpid": 1,"user": {"uid": "30009257","avatar": "http://toutiao.itheima.net/resources/images/98.jpg","uname": "黑马前端"},"content": "学前端就来黑马","ctime": "10-19 09: 00","like": 66}]
}

在package.json下添加启动命令

"serve": "json-server db.json --port 3004"

2)使用useEffect调用接口获取数据

封装Hook调用接口函数

function useGetList() {const [list, setList] = useState([]);useEffect(() => {async function getList() {const res = await axios.get('http://localhost:3004/list');setList(res.data);}getList()}, []);return {list,setList}}

调用Hook函数

 const {list, setList} = useGetList();

14.2把评论中的每一项抽象成一个独立的组件实现渲染

1)封装组件

function Item({item, onDel}) {return (<div key={item.rpid} className="reply-item">{/* 头像 */}<div className="root-reply-avatar"><div className="bili-avatar"><imgclassName="bili-avatar-img"alt=""/></div></div><div className="content-wrap">{/* 用户名 */}<div className="user-info"><div className="user-name">{item.user.uname}</div></div>{/* 评论内容 */}<div className="root-reply"><span className="reply-content">{item.content}</span><div className="reply-info">{/* 评论时间 */}<span className="reply-time">{item.ctime}</span>{/* 评论数量 */}<span className="reply-time">点赞数:{item.like}</span><span className="delete-btn" onClick={() => onDel(item.rpid)}>删除</span></div></div></div></div>);
}

2)调用组件

<div className="reply-list">{/* 评论项 */}{list.map((item) => (<Item key={item.id} item={item} onDel={deleteItem}/>))}
</div>

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

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

相关文章

C语言数据结构:排序(2)

文章目录 4.选择排序4.1 基本思想4.2 排序实现 5.快排5.1 基本思想5.2 递归实现快排5.3 快排优化5.4 双指针法完成快排5.5 快排的非递归 6.归并排序6.1 基本思想6.2 排序的实现6.3 归并排序的非递归 7. 计数排序7.1 基本思想7.2 排序实现7.3 排序的优缺点 8.排序总结 4.选择排序…

C++初阶教程——C++入门

一、本章主要内容 C在C的基础之上&#xff0c;加入了面向对象编程的思想&#xff0c;并增加了许多有用的库以及编程范式。可以说&#xff0c;C是C的子集。在这章的内容中&#xff0c;笔者将会为诸位读者讲C如何补充C语言的一些不足。比如&#xff1a;作用域、IO、函数、指针等。…

【Golang】Go语言中如何进行包管理

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

JetBrains IDE中GPU进程(JCEF)重启问题(Too many restarts of GPU-process)解决方案

目录 前言1. GPU进程重启问题概述1.1 什么是GPU进程重启问题&#xff1f;1.2 该问题带来的影响 2. GPU进程重启问题的原因分析2.1 显卡驱动的兼容性问题2.2 系统资源的限制2.3 JCEF组件的设置不合理 3. 解决方案3.1 方法一&#xff1a;通过自定义属性禁用GPU加速3.2 方法二&…

20241028在荣品PRO-RK3566开发板的预置Android13下用iperf3测试AP6256的WIFI网速

20241028在荣品PRO-RK3566开发板的预置Android13下用iperf3测试AP6256的WIFI网速 2024/10/28 18:17 荣品PRO-RK3566开发板作为服务器端&#xff1a; 笔记本电脑作为客户端。 接公司的网络。 在笔记本电脑的ubuntu20.04下&#xff0c;通过nethogs实测iperf3的发送速度大概是10MB…

410wifi的正确利用之路——debian 11

装上openwrtadguard太卡了&#xff0c;10min自启一次&#xff0c;当无线网卡都费劲。 网桥、USB千万网段要和主网独立 wifi连接激活后再改静态ip 高通410 修复debian 11的环境 1 换debian11源 &#xff08;1&#xff09;切换为国内的软件源&#xff08;可以加快软件更新时的…

压力测试Monkey命令参数和报告分析!

adb的操作命令格式一般为&#xff1a;adb shell monkey 命令参数 PART 01 常用参数 ⏩ -p <测试的包名列表> 用于约束限制&#xff0c;用此参数指定一个或多个包。指定包之后&#xff0c;Monkey将只允许系统启动指定的APP。如果不指定包&#xff0c;Monkey将允许系统…

SSA-CNN-LSTM-MATT多头注意力机制多特征分类预测

SSA-CNN-LSTM-MATT多头注意力机制多特征分类预测 目录 SSA-CNN-LSTM-MATT多头注意力机制多特征分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现SSA-CNN-LSTM-MATT麻雀算法优化卷积神经网络-长短期记忆神经网络融合多头注意力机制多特征分类预测&…

GPU 服务器厂家:中国加速计算服务器市场的前瞻洞察

科技的飞速发展&#xff0c;让 GPU 服务器在加速计算服务器领域的地位愈发凸显。中国加速计算服务器市场正展现出蓬勃的生机&#xff0c;而 GPU 服务器厂家则是这场科技盛宴中的关键角色。 从市场预测的趋势来看&#xff0c;2023 年起&#xff0c;中国加速计算服务器市场便已展…

Go第三方框架--gorm框架(二)

增删改查&#xff08;dml操作&#xff09; 查询操作 gorm查询主要执行了三种操作&#xff1a; 通过链式函数调用累计查询条件&#xff08;在map[string]clause.Clause中累计&#xff09;将查询条件转换成sql&#xff08;赋值给 Statement.SQL和Statement.Vals&#xff09;执…

A Simple Semi-Supervised Learning Framework for Object Detection

1. Introduction SSL的成功主要有以下两个方面&#xff1a; &#xff08;1&#xff09;一致性正则化&#xff1a;如果对一个未标记的数据应用实际的扰动, 其预测结果不应该发生显著变化, 也就是输出具有一致性&#xff0c;通过在未标记数据上构造添加扰动后的预测结果 y~​ 与…

【51 Pandas+Pyecharts | 深圳市共享单车数据分析可视化】

文章目录 &#x1f3f3;️‍&#x1f308; 1. 导入模块&#x1f3f3;️‍&#x1f308; 2. Pandas数据处理2.1 读取数据2.2 查看数据信息2.3 处理起始时间、结束时间2.4 增加骑行时长区间列2.5 增加骑行里程区间列 &#x1f3f3;️‍&#x1f308; 3. Pyecharts数据可视化3.1 各…

webGlL变量的声明与使用

抢先观看&#xff1a; 变量的声明格式&#xff1a;<存储限定符><类型限定符><变量名> 存储限定符&#xff1a;const, attribute, uniform, varying, buffer。 类型限定符&#xff1a;void, bool, int, float, double, vec2, vec3, vec4, mat2, mat3, mat4, s…

基于SSM的成都市旅游信息管理系统-计算机毕业设计源码65815

SSM成都市旅游信息管理系统 摘 要 本论文主要论述了如何使用SSM框架开发一个旅游信息管理系统&#xff0c;严格按照软件开发流程进行各个阶段的工作&#xff0c;采用B/S架构JAVA技术&#xff0c;面向对象编程思想进行项目开发。在引言中&#xff0c;作者将论述旅游信息管理系…

91.【C语言】数据结构之单向链表的头删和尾删

目录 1.尾删函数SLTPopBack 代码示例(写入SList.c) 在SList.h中写入该函数的声明 main.c部分代码改为 ​编辑 分析 解决方法 方法1:双指针算法(快指针tail,慢指针pretail) 方法2 2.头删函数SLTPopFront 一个节点示意图 多个节点示意图 代码示例(写入SList.c) 在S…

DEVOPS: 集群伸缩原理

概述 阿里云 K8S 集群的一个重要特性&#xff0c;是集群的节点可以动态的增加或减少有了这个特性&#xff0c;集群才能在计算资源不足的情况下扩容新的节点&#xff0c;同时也可以在资源利用 率降低的时候&#xff0c;释放节点以节省费用理解实现原理&#xff0c;在遇到问题的…

华为OD机试 - 无向图染色(Java 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;E卷D卷A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加…

云智慧完成华为原生鸿蒙系统的适配, 透视宝 APM 为用户体验保驾护航

2024 年 10 月 22 日&#xff0c;首个国产移动操作系统 —— 华为原生鸿蒙操作系统 HarmonyOS NEXT 正式面世&#xff0c;成为继 iOS 和 Android 后的全球第三大移动操作系统。HarmonyOS NEXT&#xff0c;从系统内核、数据库根基&#xff0c;到编程语言创新、AI&#xff08;人工…

无人机之任务分配算法篇

无人机的任务分配算法是无人机系统中的重要组成部分&#xff0c;它决定了无人机如何高效、合理地执行各种任务。以下是一些常见的无人机任务分配算法&#xff1a; 一、合同网协议&#xff08;Contract Net Protocol, CNP&#xff09; 基本概念&#xff1a;CNP算法是一种分布式…

【WRF数据处理】基于GIS4WRF插件将geotiff数据转为tiff(geogrid,WPS所需数据)

【WRF数据处理】基于GIS4WRF插件将geotiff数据转为tiff&#xff08;geogrid&#xff0c;WPS所需数据&#xff09; 数据准备&#xff1a;以叶面积指数LAI为例QGis实操&#xff1a;基于GIS4WRF插件将geotiff数据转为tiff警告&#xff1a;GIS4WRF: Input layer had an unexpected …