# react-class **Repository Path**: tease-not-bald/react-class ## Basic Information - **Project Name**: react-class - **Description**: 逗逗的 react 学习之路😮 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2023-12-22 - **Last Updated**: 2024-03-01 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # react-class 逗逗的 react 学习之路😮 # JS基础 js_basics [React预备知识 – 李立超 | lilichao.com](https://www.lilichao.com/index.php/2022/03/18/react预备知识/); # React基础 react_basics + [React | 官网](https://react.dev/); + [React 官方中文文档 (docschina.org)](https://react.docschina.org/); 可能同步会有延迟,或直接不同步; + [React12_React简介_哔哩哔哩_bilibili | 该课程打基础](https://www.bilibili.com/video/BV1bS4y1b7NV?p=13&vd_source=133ec2d20ab75cd55a5b84e3d0e80962); ## React简介 > React的特点: > > - 虚拟DOM > - 声明式 > - 基于组件 > - 支持服务器端渲染 > - 快速、简单、易学 ## HelloWorld React的常规开发方式并不是通过浏览器引入外部js脚本来使用,但在入门阶段我们暂且先使用这种方式来简单体会一下React。 使用React开发Web项目,我们需要引入两个js脚本:(文件在 `react_basics/js` 里) - **react.development.js:**react 是react核心库,只要使用react就必须要引入 - **react-dom.development.js:**react-dom 是react的dom包,使用react开发web应用时必须引入 - 新建 **index.html:**写代码呀 以往的写法: ~~~html Hello World
~~~ 采用React后的写法: ~~~html Hello World
~~~ ## React三大API > + **React.createElement()**:用来出创建一个React元素 > > ​ 参数: > > 1. 元素名(组件名、html标签必须小写) > > 2. 元素的属性 > > 3. 在设置事件时 > > - 事件名使用驼峰命名法,后面跟事件函数 > > - 在设置class时,class使用className > > 4. 元素的子元素(内容) > > 5. `注意点`: > > - React元素最终会通过虚拟DOM转化为真实的DOM元素 > > - React元素一旦创建无法修改,只能通过新创建的元素进行替换 > > + **ReactDOM.createRoot()** > > 获取根元素,根元素就是React元素要插入的位置 > > + **root.render()** > > 用来将React元素渲染到根元素中 > > 根元素中所有的内容都会被删除,被React元素所替换 > > 当重复调用render()时,React会将两次的渲染结果进行比较 > > ​ 他会确保只修改那些发生变化的元素,对DOM做最少的修改 ~~~html
~~~ 看这代码会不会非常麻烦,老是创建再创建的,后面用脚手架后,就会有东西自动帮我们做了。 ## JSX > + 创建一个React元素 `` > > 命令式编程 > > + const button = React.createElement('button', {}, '我是按钮'); > > 声明式编程,结果导向的编程 > > 在React中可以通过JSX(JS扩展)来创建React元素,JSX需要被翻译为JS代码,才能被React执行 > > + 要在React中使用JSX,必须引入babel来完成“翻译”工作 > > babel下载地址:https://unpkg.com/babel-standalone@6/babel.min.js > > JSX就是React.createElement()的语法糖,JSX在执行之前都会被babel转换为js代码 ~~~html Hello World
~~~ ### JSX注意 >+ JSX的注意事项 > > 1. JSX不是字符串,不要加引号 > > 2. JSX中html标签应该小写,React组件应该大写开头 > > 3. JSX中有且只有一个根标签 > > 4. JSX的标签必须正确结束(自结束标签必须写/) > > 5. 在JSX中可以使用{}嵌入表达式 > > 有值的语句的就是表达式 > > 6. 如果表达式是空值、布尔值、undefined,将不会显示 > > 7. 在JSX中,属性可以直接在标签中设置 > > 注意: > > ​ class需要使用className代替 > > ​ style中必须使用对象设置style={{background:'red'}} ~~~html ~~~ ### 渲染列表 > {} 只能用来放js表达式,而不能放语句(if for) > > 但在语句中是可以去操作JSX ~~~html
~~~ 将 `const data = ['孙悟空', '猪八戒', '沙和尚'];` 用列表展示: ~~~html
~~~ ## 虚拟DOM > + 在React我们操作的元素被称为React元素,并不是真正的原生DOM元素,React通过虚拟DOM 将React元素 和 原生DOM,进行映射,虽然操作的React元素,但是这些操作最终都会在真实DOM中体现出来。 > + 虚拟DOM的好处: > 1. 降低API复杂度 > 2. 解决兼容问题 > 3. 提升性能(减少DOM的不必要操作) > + 每当我们调用root.render()时,页面就会发生重新渲染,React会通过diffing算法,将新的元素和旧的元素进行比较,通过比较找到发生变化的元素,并且只对变化的元素进行修改,没有发生的变化不予处理 ~~~html
~~~ > 旧数据 > > ul > > ​ li>孙悟空 > > ​ li>猪八戒 > > ​ li>沙和尚 > > 新数据 > > ul > > ​ li>孙悟空 > > ​ li>猪八戒 > > ​ li>沙和尚 > > 比较两次数据时,React会先比较父元素,父元素如果不同,直接所有元素全部替换,父元素一致,在去逐个比较子元素,直到找到所有发生变化的元素为止,上例中,新旧两组数据完全一致,所以没有任何DOM对象被修改 > > 当我把数据该了 > > ul > > ​ li>Tom > > ​ li>猪八戒 > > ​ li>沙和尚 > > 当我们在JSX中显示数组中,数组中每一个元素都需要设置一个唯一key,否则控制台会显示红色警告 > > ul > > ​ li>孙悟空 > > ​ li>猪八戒 > > ​ li>沙和尚 > > ​ li>唐僧 > > 在列表的最后添加了一个新元素,并没有改变其他的元素的顺序,所以这种操作不会带来性能问题 > > 在列表的最前边插入了一个新元素,其他元素内容并没有发生变化,但是由于新元素插入到了开始位置,其余元素的位置全都发生变化,而React默认是根据位置比较元素,所以 此时,所有元素都会被修改 > > 为了解决这个问题,React为列表设计了一个key属性,key的作用相当于ID,只是无法在页面中查看,当设置key以后,再比较元素时,就会比较相同key的元素,而不是按照顺序进行比较,在渲染一个列表时,通常会给列表项设置一个唯一的key来避免上述问题(这个key在当前列表中唯一即可) > > 注意: > > 1. 开发中一般会采用数据的id作为key > 2. 尽量不要使用元素的index作为key > 3. 索引会跟着元素顺序的改变而改变,所以使用索引做key跟没有key是一样的 > 4. 唯一的不同就是,控制台的警告没了 > 5. 当元素的顺序不会发生变化时,用索引做key也没有什么问题 ~~~html
~~~ # React脚手架 react_scaffold 常规的React项目需要使用npm(或yarn/pnpm)作为包管理器来对项目进行管理。并且React官方为了方便我们的开发,为我们提供react-scripts包(提供个webpack、测试等一系列内置依赖,**约定优于配置**)。包中提供了项目开发中的大部分依赖,大大的简化了项目的开发。 ## 手动创建React项目 construct_hand + 目录结构: ~~~bash construct_hand - public - index.html (添加标签
) - src - App.js - index.js ~~~ + 再项目根目录 `manual_operation` 下执行命令: ~~~cmd npm init -y # or yarn init -y # or pnpm init ~~~ + 安装项目依赖: ~~~cmd npm install react react-dom react-scripts -S # or yarn add react react-dom react-scripts # or pnpm install react react-dom react-scripts ~~~ + 各文件必须配置: ~~~html // index.html React for hand construct
~~~ ~~~js // App.js const App = (

Hello World

); export default App; ~~~ ~~~js // index.js import ReactDOM from "react-dom/client"; import App from "./App"; const root = ReactDOM.createRoot(document.getElementById("root")); root.render(App); ~~~ ~~~json // package.json "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, ~~~ + 运行: ~~~cmd npm run start # or yarn start # or pnpm start ~~~ ## 学习日志 learning_journal + 手动创建React项目基本结构 + 配置eslint检查: ~~~json // package.json "eslintConfig": { "extends": "react-app" }, ~~~ + 大致布局: ~~~js // App.js const App = (
{/* 日志项容器 */}
{/* 日期 */}
四月
12
{/* 内容 */}

学习React

40分钟
); export default App; ~~~ + 编写样式:在 `src` 下新启个文件 `App.css` ~~~css /* 基本样式 */ * { box-sizing: border-box; } /* body样式 */ body { background-color: #f4f4f4; margin: 0; } /* 外层容器logs样式 */ .logs { width: 800px; margin: 50px auto; padding: 20px; border-radius: 12px; background-color: #eae2b7; box-shadow: 0 0 12px rgba(0, 0, 0, 0.2); } /* 日志项样式 */ .item { display: flex; border-radius: 12px; margin: 16px 0; padding: 8px; background-color: #fcbf49; box-shadow: 0 0 12px rgba(0, 0, 0, 0.2); } /* 日期样式 */ .date { width: 90px; background-color: #fff; border-radius: 10px; font-weight: bold; text-align: center; overflow: hidden; } /* 月份样式 */ .month { height: 30px; line-height: 30px; color: #fff; background-color: #d62828; } /* 日期样式 */ .day { height: 60px; line-height: 60px; font-size: 50px; } /* 内容样式 */ .content { flex: auto; text-align: center; } .desc { font-size: 16px; color: #003049; } .time { font-size: 14px; font-weight: bold; color: #de462b; } ~~~ + 将样式文件引入 `App.js` : ~~~js import "./App.css"; ~~~ # React > 掌握react中的基本语法 ## React组件 for_module 在React中网页被拆分为了一个一个组件,组件是独立可复用的代码片段。具体来说,组件可能是页面中的一个按钮,一个对话框,一个弹出层等。React中定义组件的方式有两种:基于函数的组件和基于类的组件。本节我们先看看基于函数的组件。 + 基于函数的组件其实就是一个会返回JSX(React元素)的普通的JS函数,你可以这样定义: ~~~js // App.js // function App() { // return

我是一个React的组件!

; // } // 箭头函数 const App = () => { return

我是一个React的组件!

; }; // 导出App组件 export default App; ~~~ + 渲染组件:引入后通过`<组件名/>`或`<组件名>`即可引入组件 ~~~js // index.js root.render(); ~~~ + 在一个组件中可以直接使用其他组件: ~~~js // Button.js const Button = () => { return ; }; export default Button; ~~~ + 在`App.js`中可以直接引入该组件: ~~~js import Button from "./Button"; const App = () => { return (

我是一个React的组件!

); }; // 导出App组件 export default App; ~~~ + 除了函数组件外,在React中还有一种类组件,但类组件使用起来并不方便,所以在React中类组件的使用场景越来越少:新建 `H2.js` 组件 ~~~js // 类组件 import React from "react"; // 类组件必须要继承React.Component class H2 extends React.Component { // 类组件必须添加一个render,且返回值要是一个js render() { return

我是一个类组件

; } } export default H2; ~~~ ## 学习日志 learning_journal 组件化 创建 `src/Components` 组件都会放到这里,当让你也可以在该目录下再去细分组件目录,我这就不写了: ~~~js // Logs.js import LogItem from "./LogItem"; const Logs = () => { return (
); }; export default Logs; // LogItem.js import MyDate from "./MyDate"; const LogItem = () => { return (
{/* 日期 */} {/* 内容 */}

学习React

40分钟
); }; export default LogItem; // MyDate.js const MyDate = () => { return (
四月
12
); }; export default MyDate; // App.js import "./App.css"; import Logs from "./Components/Logs"; const App = () => { return (
); }; export default App; ~~~ 到这里就完成了,但是还是不太好,样式应该对应创建并对应引入: ~~~css // Logs.css /* 外层容器logs样式 */ .logs { width: 800px; margin: 50px auto; padding: 20px; border-radius: 12px; background-color: #eae2b7; box-shadow: 0 0 12px rgba(0, 0, 0, 0.2); } // LogItem.css /* 日志项样式 */ .item { display: flex; border-radius: 12px; margin: 16px 0; padding: 8px; background-color: #fcbf49; box-shadow: 0 0 12px rgba(0, 0, 0, 0.2); } /* 内容样式 */ .content { flex: auto; text-align: center; } .desc { font-size: 16px; color: #003049; } .time { font-size: 14px; font-weight: bold; color: #de462b; } // MyDate.css /* 日期样式 */ .date { width: 90px; background-color: #fff; border-radius: 10px; font-weight: bold; text-align: center; overflow: hidden; } /* 月份样式 */ .month { height: 30px; line-height: 30px; color: #fff; background-color: #d62828; } /* 日期样式 */ .day { height: 60px; line-height: 60px; font-size: 50px; } ~~~ ## 事件 > 在React中事件需要通过元素的属性来设置,和原生JS不同,在React中事件的属性需要使用驼峰命名法:onclick -> onClick。属性值不能直接执行代码,而是需要一个回调函数:onClick={()=>{alert(123)}} ~~~js return ~~~ + 触发一个函数: ~~~js const Button = () => { const handleClick = () => { alert("Clicked!"); }; return (
); }; export default Button; ~~~ + 在React中,无法通过return false取消默认行为,用事件对象:React事件中同样会传递事件对象,可以在响应函数中定义参数来接收事件对象,React中的事件对象同样不是原生的事件对象,是经过React包装后的事件对象,由于对象进行过包装,所以使用过程中我们无需再去考虑兼容性问题 ~~~js const Button = () => { const handleClick = (event) => { event.preventDefault(); // 阻止默认行为 alert("Clicked!"); }; return (
超链接
); }; export default Button; ~~~ + 取消事件的冒泡:就是事件的向上触发 ~~~js const Button = () => { const handleClick = (event) => { event.stopPropagation(); // 取消事件的冒泡 alert("Clicked!"); }; return (
{ alert("我是div"); }} >
); }; export default Button; ~~~ ## props 在一个组件向另一个组件传递数据 > 之前我们所定义的组件内容几乎都是固定的,组件创建的时候什么样,使用时就是什么样。但在开发时,我们往往需要的是一些动态显示的组件,换句话组件中所显示的内容必须是动态设置的。 > > 在使用组件时,可以通过向组件传递参数的形式来向组件传递数据,这一点和JS中的函数非常相似。函数可以通过传递实参来决定函数的执行结果,组件也不例外。函数的参数如何传递我们是非常清楚的,那么组件的参数是怎么传递的呢?组件的参数需要通过属性传递,可以像这样向组件中传递参数: > > + 在函数组件中,属性就相当于是函数的参数,可以通过参数来访问 > + 可以在函数组件的形参中定义一个props,props指向的是一个对象 > + 它包含了父组件中传递的所有参数 > + 如果将组件中的数据全部写死,将会导致组件无法动态设置,不具有使用价值,我们希望组件数据可以由外部设置,在组件间,父组件可以通过props(属性)向子组件传递数据 > + props是只读属性,不可修改 ~~~js // 父组件Logs.js import LogItem from "./LogItem"; import "./Logs.css"; const Logs = () => { return (
); }; export default Logs; // 子组件LogItem.js import MyDate from "./MyDate"; import "./LogItem.css"; const LogItem = (props) => { console.log(props); return (
{/* 日期 */} {/* 内容 */}

{props.desc}

{props.time}分钟
); }; export default LogItem; ~~~ 设置日期: ~~~js // 子组件LogItem.js {/* 日期 */} // 孙组件MyDate.js import "./MyDate.css"; const MyDate = (props) => { console.log(props.date); const month = props.date.toLocaleString("zh-CN", { month: "long" }); const day = props.date.getDate(); return (
{month}
{day}
); }; export default MyDate; ~~~ + 模拟一条从服务器加载的数据: ~~~js import LogItem from "./LogItem"; import "./Logs.css"; const Logs = () => { // 模拟一条从服务器加载的数据 const logsData = [ { id: "1", date: new Date(2021, 2, 26, 19, 0), desc: "学习Nest", time: "50" }, { id: "2", date: new Date(2022, 5, 16, 6, 30), desc: "学习vue", time: "80" }, { id: "3", date: new Date(2023, 12, 26, 12, 30), desc: "学习React", time: "60" } ]; // 遍历 const logItemData = logsData.map((item) => ( )); return (
{/* */} {/* 遍历 */} {logItemData}
); }; export default Logs; ~~~ ## state 数据发生变化时自动重新渲染 + 抛出问题:实行一个计数器 ~~~js import "./App.css"; const App = () => { let counter = 0; const addHandler = () => { // 点击后数字+1 // alert('+1'); counter++; }; const lessHandler = () => { // 点击后数字-1 // alert('-1'); counter--; }; return (

{counter}

); }; export default App; ~~~ **结果你会发现,不管你咋点击,那个数值都不会变,这是为啥子呢?** > + 在React中,当组件渲染完毕后,再修改组件中的变量,不会使组件重新渲染 > + 要使得组件可以收到变量的影响,必须在变量修改后对组件进行重新渲染 > + 这里我们就需要一个特殊变量,当这个变量被修改使,组件会自动重新渲染 > + state相当于一个变量: > - state只属于当前组件,其他组件无法访问。并且state是可变的,当其发生变化后组件会自动重新渲染,以使变化在页面中呈现 > - 只是这个变量在React中进行了注册,React会监控这个变量的变化,当state发生变化时,会自动触发组件的重新渲染,使得我们的修改可以在页面中呈现出来 > + 在函数组件中,我们需要通过钩子函数,获取state,使用钩子 useState() 来创建state,import {useState} from "react"; > + 它需要一个值作为参数,这个值就是state的初始值,该函数会返回一个数组,数组中第一个元素,是初始值,初始值只用来显示数据,直接修改不会触发组件的重新渲染,数组中的第二个元素,是一个函数,通常会命名为setXxx > + 这个函数用来修改state,调用其修改state后会触发组件的重新渲染,并且使用函数中的值作为新的state值 ~~~js import "./App.css"; import { useState } from "react"; const App = () => { const [counter, setCounter] = useState(1); const addHandler = () => { // 点击后数字+1 // alert('+1'); // counter++; setCounter(counter + 1); // 将counter值修改为2 }; const lessHandler = () => { // 点击后数字-1 // alert('-1'); // counter--; setCounter(counter - 1); // 将counter值修改为0 }; return (

{counter}

); }; export default App; ~~~ ### state 的问题 > + state实际就是一个被React管理的变量,当我们通过setState()修改变量的值时,会触发组件的自动重新渲染 > + 只有state值发生变化时,组件才会重新渲染 > + 当state的值是一个对象时,修改时是使用新的对象去替换已有对象 > + 当通过setState去修改一个state时,并不表示修改当前的state,它修改的是组件下一次渲染时state值 > + setState()会触发组件的重新渲染,它是异步的,所以当调用setState()需要用旧state的值时,一定要注意,有可能出现计算错误的情况,为了避免这种情况,可以通过为setState()传递回调函数的形式来修改 ~~~js import "./App.css"; import { useState } from "react"; const App = () => { const [counter, setCounter] = useState(1); const [user, setUser] = useState({ name: "孙悟空", age: 18 }); const addHandler = () => { // setCounter(counter + 1); // 将counter值修改为2 setTimeout(() => { setCounter((prevCounter) => { /* * setState()中回调函数的返回值将会成为新的state值 * 回调函数执行时,React会将最新的state值作为参数传递 * */ return prevCounter + 1; }); }, 1000); }; const updateUserHandler = () => { // setUser({name:'猪八戒'}); // 如果直接修改旧的state对象,由于对象还是那个对象,所以不会生效 // user.name = '猪八戒'; // console.log(user); // setUser(user); // const newUser = Object.assign({}, user); // newUser.name = '猪八戒'; // setUser(newUser); setUser({ ...user, name: "猪八戒" }); }; return (

{counter}--{user.name}--{user.age}

); }; export default App; ~~~ ## Ref(获取原生DOM对象)useRef() > React中所有的操作默认都是在React元素上进行,然后再通过虚拟DOM应用到真实页面上的。在React中依然为我们提供了可以直接访问原生DOM对象的方式。ref就是干这个事的。**尽量是读取而不要修改,如果必需要修改也要尽量减少修改的次数,总之能不用就不用** > > + 获取原生的DOM对象: > 1. 可以使用传统的document来对DOM进行操作 > 2. 直接从React处获取DOM对象 > + 创建一个存储DOM对象的容器 > + 使用 useRef() 钩子函数 > + 钩子函数的注意事项: > 1. React中的钩子函数只能用于函数组件或自定义钩子 > 2. 钩子函数只能直接在函数组件中调用 > + 将容器设置为想要获取DOM对象元素的ref属性,

....

> + React会自动将当前元素的DOM对象,设置为容器current属性 > > * useRef() > * - 返回的就是一个普通的JS对象 > * - {current:undefined} > * - 所以我们直接创建一个js对象,也可以代替useRef() > * - 区别: > * 我们创建的对象,组件每次重新渲染都会创建一个新对象 > * useRef()创建的对象,可以确保每次渲染获取到的都是同一个对象 > * - 当你需要一个对象不会因为组件的重新渲染而改变时,就可以使用useRef() ~~~js import "./App.css"; import { useRef, useState } from "react"; const App = () => { // 获取原生DOM对象 const h1Ref = useRef(); // 创建一个容器 const [count, setCount] = useState(1); const clickHandler = () => { console.log(h1Ref); // alert(h1Ref.current === header); h1Ref.current.innerText = "嘻嘻!"; }; const countAddHandler = () => { setCount((prevState) => prevState + 1); }; return (

我是标题{count}

); }; export default App; ~~~ ## 类组件 class_module > 使用类组件时: > > + 你可以用 `class User extends React.Component {}`/ `class User extends Component {}` 都可以,然后引入 `import React, { Component } from "react"` > + 使用夫传子时,可以不定义一个`props` ,可以直接使用 `this.props` 。 > + `state` 统一存储到了实例对象中的 `state` 属性中,可以通过 `this.state` 来访问,通过 `this.setState()` 对其进行修改。 > + 函数组件中,响应函数直接以函数的形式定义在组件中。但是在类组件中,响应函数是以类的方法来定义的 > + 当使用 `this.setState()` 对 `state` 进行修改时,React只会修改设置的属性 > + 获取DOM对象:创建一个属性,用来存储DOM对象,`divRef = React.createRef()` ,将这个属性设置在指定元素的ref中 ~~~js // components/User.js import React, { Component } from "react"; class User extends Component { // 创建一个DOM对象 divRef = React.createRef(); state = { count: 0, text: "haha", obj: { name: "zhangsan", age: 18 } }; clickHandler = () => { // this.setState({ count: this.state.count + 1 }); // this.setState((prevState) => { // return { count: prevState.count + 1 }; // }); // this.setState({ // obj: { // ...this.state.obj, // age: this.state.obj.age + 1 // } // }); console.log(this.divRef); }; render() { return (

{this.state.count}---{this.state.text}

{this.state.obj.name}---{this.state.obj.age}

  • 姓名:{this.props.name}
  • 性别:{this.props.sex}
  • 年龄:{this.props.age}
); } } export default User; // App.js import "./App.css"; import { Component } from "react"; import User from "./components/User"; class App extends Component { render() { return (

Hello CodeSandbox

); } } export default App; ~~~ ### 给日历案例新增添加功能 > 在 `components/UI` 目录一般放全局使用的组件,然后新增 `Card/Card.js` 。 ~~~js import "./Card.css"; const Card = (props) => { return
{props.children}
; }; export default Card; ~~~ 然后就可以在其他组件中用了 实现通过表单添加一个新的实例 ~~~js import React, { useState } from "react"; import Card from "../UI/Card/Card"; import "./LogForm.css"; const LogForm = () => { // 当表单项发生变化时,获取用户输入的内容 // 创建三个变量,用来存储表单中的数据 const [inputDate, setInputDate] = useState(""); const [inputDesc, setInputDesc] = useState(""); const [inputTime, setInputTime] = useState(""); // 创建一个响应函数,监听日期的变化 const dateChangeHandler = (e) => { // 获取到当前触发事件的对象 setInputDate(e.target.value); }; // 监听内容的变化 const descChangeHandler = (e) => { // 获取到当前触发事件的对象 setInputDesc(e.target.value); }; //监听时长的变化 const timeChangeHandler = (e) => { // 获取到当前触发事件的对象 setInputTime(e.target.value); }; // 当表单提交时,汇总表单中的数据 /* * 在React中,通常表单不需要自行提交 * 而是要通过React提交 * */ const formSubmitHandler = (e) => { // 取消表单的默认行为 e.preventDefault(); // 获取表单项中的数据日期、内容、时长 // 将数据拼装为一个对象 const newLog = { date: new Date(inputDate), desc: inputDesc, time: +inputTime }; setInputDate(""); setInputDesc(""); setInputTime(""); console.log(newLog); }; return (
); }; export default LogForm; ~~~ > logsDate 用来存储学习的日志: > > 这个数据除了当前组件Logs需要使用外,LogsForm也需要使用 > > 当遇到一个数据需要被多个组件使用时,我们可以将数据放入到这些组件共同的祖先元素中 > > 这样就可以使得多个组件都能方便的访问到这个数据 > > state的提升 # 黑马课程 视频:[Day1-02.React开发环境创建_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1ZB4y1Z7o8/?p=3&vd_source=133ec2d20ab75cd55a5b84e3d0e80962) 采用 `create-react-app` 创建react项目: ~~~cmd npx create-react-app comment ~~~ ## 评论案例 comment + 渲染初始数据的评论列表,通过 `map()` 方法,由于后面会列表会发生变化,采用 `useState()` 动态渲染数据。 ~~~js import { useState } from "react"; const App = () => { const [commentList, setcommentList] = useState(defaultList); return (
{/* 导航 Tab */}
  • 评论 {/* 评论数量 */} {10}
  • {/* 高亮类名: active */} 最新 最热
{/* 发表评论 */}
{/* 当前用户头像 */}
用户头像
{/* 评论框 */}