当前位置: 首页 > news >正文

【前端学习】React学习【万字总结】

React学习

React组件与jsx

使用jsx编写,最纯粹的js开发

React组件可以是一个方法,也可以是一个class

可以直接在js文件里写一段html来作为一个组件,也可以写成一个单独的jsx或者js文件

import logo from './logo.svg'; // 导入一个 SVG 格式的 logo 图片
import './App.css' // 导入组件的样式文件,为当前组件添加视觉样式

function App() { // App组件
return ( // JSX 结构,描述页面 UI
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}

export default App; // 是 ES6 模块系统中的语法,作用是将 App 这个组件设置为当前模块(即 App.js 文件)的默认导出项,方便其他模块导入使用

这是一个 函数式组件(React 中定义组件的方式之一),组件的 UI 由返回的 JSX(JavaScript XML,一种类似 HTML 的语法,用于描述 React 组件的结构)描述

function App() {
return (
// JSX 结构,描述页面 UI
);
}

React组件分类

  1. 函数组件(配合Hook使用)
  1.  Hello() {
    return (
    <div>
    <p>hello</p>
    </div>
    );
    }
  1. Class组件
  1.  Hello extends React.Component { // 这个类继承自 React 内置的 Component 类
    render() {
    return ( // 返回组件要渲染的 UI 结构(通过 JSX 描述),这里返回的 JSX 结构是:一个 <div> 容器,里面包含一个 <p> 标签,标签内的文本是 hello
    <div>
    <p>hello</p>
    </div>
    )
    }
    }

React 组件的命名惯例是首字母大写

jsx的特点

  1. 可以直接写在js文件中
  1. 项目利用babel做了对js的编译,所以可以直接在js里写jsx的
  1. 写法接近js
  1. 几乎和js一样,不同点就在于,可以更方便地写html在js里

初始化react项目

创建react项目

npx create-react-app <projectName>

npx 是 npm 5.2版本后自带的一个工具,让我们可以不用安装脚手架直接去使用的一些包

npx之前:如果你想使用某个 Node 包的可执行命令(比如 create-react-app 来创建 React 项目),通常有两种麻烦的方式:

  1. 全局安装:执行 npm install -g create-react-app,然后再运行 create-react-app my-app。但这样会导致:全局空间被占用,时间久了容易堆积大量 “只偶尔用一次” 的工具;不同项目可能需要不同版本的工具,全局安装无法灵活切换。
  2. 本地安装 + 手动执行:先在项目里 npm install create-react-app,再去 node_modules/.bin 目录里找可执行文件运行,步骤繁琐。

npx 的核心是 “临时执行,用完即走”

  1. 运行 npx <命令> 时,它会先在本地项目的 node_modules/.bin 目录中查找对应的可执行文件;
  2. 如果本地没有,就会去远程 npm 仓库下载对应的包(临时下载,执行完不会残留全局安装的包);
  3. 执行命令后,临时下载的包会被自动清理,不会占用本地空间。

创建完成后会得到如下内容:

默认目录结构

  1. node_modules:存放项目的所有依赖包(通过 npm install 安装的第三方库都会存放在这里),是项目运行的依赖基础
  2. public:存放静态资源,这些资源不会被 Webpack 编译,直接以原始形式被浏览器访问。常见内容包括:
    • index.html:React 应用的HTML 模板(应用最终会被注入到这个文件的 <div id="root"></div> 中);
    • favicon.ico:浏览器标签页的图标;
    • 其他静态文件(如图片、第三方脚本等)
  3. src:存放项目源码,是开发的核心区域,包含组件、样式、入口文件等。典型内容有:
    • index.js:应用的入口文件,负责将根组件渲染到 public/index.html 的 root 节点中;
    • 各种 React 组件(如 App.js);
    • 样式文件(如 index.css、App.css);
    • 资源文件(如图片、SVG 等)。
  4. .gitignore:配置 Git 版本控制的 “忽略规则”,指定哪些文件 / 目录不需要被 Git 追踪
  5. package-lock.json锁定依赖版本的文件,确保在不同环境(如开发机、测试机、生产机)中安装的依赖版本完全一致,避免 “依赖版本不一致导致的 Bug”
  6. package.json:项目的核心配置文件,包含:
    • 项目信息(名称、版本、描述等);
    • 依赖包列表(dependencies 是生产依赖,devDependencies 是开发依赖);
    • 脚本命令(如 start、build、test 等,可通过 npm run <脚本名> 执行)‘
  7. README.md:项目的说明文档,通常包含项目介绍、安装步骤、运行方式、功能说明等信息,方便其他开发者了解和使用项目

index.html 和 index.js 是启动应用的核心文件

  1. public/index.html:HTML 模板载体:位置:位于 public 目录下。作用:是 React 应用在浏览器中渲染的 “容器页面”
    1. 它包含一个关键的 <div id="root"></div>,React 应用的所有组件最终都会注入到这个 div ,形成完整的页面 UI。
    2. 还可用于配置页面元信息(如 <meta> 标签、标题)、静态资源(如 favicon.ico、第三方脚本)等
    3. <!DOCTYPE html> // 声明文档类型为 HTML5,用于规范浏览器的解析行为
      <html>
      <head> // 用于定义页面的元信息(不直接显示在页面主体的内容)
      <title>React App</title> // 设置浏览器标签页的标题
      </head>
      <body> // 包含页面的可见内容
      <!-- React 应用的注入点 -->
      <div id="root"></div> // React 应用的挂载点,React 通过 JavaScript 代码生成的所有组件、交互内容,最终都会被 “注入” 到这个 div 中,成为页面的实际内容。
      </body>
      </html>
  2. src/index.js:应用入口与渲染桥梁:位置:位于 src 目录下。作用:是 React 应用的 “启动入口”,负责将 React 组件渲染到index.html中。
    1. 它通过 ReactDOM.render() 方法,把根组件(通常是 App.js)“挂载” 到 index.html 的 root 节点上。
    2. 是连接 “React 组件逻辑” 和 “HTML 页面” 的桥梁,应用的执行流程从这里开始。
    3. import React from 'react'; // 导入 react 库的核心模块
      import ReactDOM from 'react-dom/client'; // 导入 react-dom/client 模块,它提供了将 React 组件渲染到浏览器 DOM 中的工具
      import App from './App'; // 导入根组件

      const root = ReactDOM.createRoot(document.getElementById('root')); // 获取 HTML 页面中 id="root" 的 DOM 元素,基于这个 DOM 元素创建一个 React 根节点(root),后续所有 React 组件都会通过这个根节点渲染到页面上
      root.render( // 调用根节点的 render 方法,将组件渲染到 DOM 中
      <React.StrictMode> // React 的 “严格模式”
      <App /> // 被渲染的根组件,App 组件的内容会被解析为 DOM 元素,并最终显示在 id="root" 的 div 中
      </React.StrictMode>
      );

当启动 React 项目时:

  1. Webpack 会从 src/index.js 开始打包所有源码;
  2. index.js 会把根组件 <App /> 渲染到 public/index.html 的 root 节点中;
  3. 最终在浏览器中,你看到的页面就是 index.html 承载的、由 React 组件渲染出的完整 UI。

Webpack 是一个前端模块打包工具,核心作用是将项目中分散的JS、CSS、图片、字体等各类资源(都视为 “模块”),经过处理后打包成一个或多个静态文件,从而优化前端项目的加载性能、管理模块依赖,并支持各种高级特性。它会从一个“入口文件”开始,递归分析所有依赖的模块,然后将这些模块合并、转换、优化 **,最终输出少数几个(甚至一个)“打包后的文件”,让浏览器可以高效加载。

像 Create React App、Vue CLI 这类脚手架工具,底层都是基于 Webpack 封装的。它们把 Webpack 的复杂配置隐藏起来,让开发者可以 “开箱即用”,但核心的打包、资源处理逻辑还是由 Webpack 完成的。

  1. 在App.js中创建App组件:
  2. 在index.js中引入App组件
  3. 将App组件渲染到index.html中

package.json文件:

"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
}

package.json 中用于定义npm 脚本命令的配置

  1. start:执行 react-scripts start启动本地开发服务器,开启热更新功能。开发时运行 npm run start,可以在浏览器中实时预览代码修改的效果。
  2. build:执行 react-scripts build构建生产环境代码。它会对项目进行压缩、优化、打包,最终生成可部署的静态文件(存放在 build 目录),这些文件可直接部署到服务器上运行。
  3. test:执行 react-scripts test启动测试运行器(默认是 Jest),用于执行项目中的单元测试和集成测试,确保代码逻辑的正确性。
  4. eject:执行 react-scripts eject这是一个不可逆操作。Create React App 封装了 Webpack、Babel 等工具的配置,执行 npm run eject 会将所有隐藏的配置文件暴露出来,让你可以完全自定义构建流程。但执行后无法再回到 “封装状态”,需谨慎使用。

运行react项目

npm run start

启动本地开发服务器,跑开发模式

在App.js中定义的内容

React的state

state是组件要用的数据

前端框架(React、Vue)实现 “数据响应式展示:前端的核心任务之一是把从后端(或其他渠道)获取的数据呈现到页面上,且当数据更新时,页面要自动响应变化(无需手动操作 DOM)

这类框架的价值就在于 “让数据和页面联动”—— 把请求到的数据渲染到页面,且数据更新时,页面能自动同步新数据

React 中的state是组件的 “响应式数据容器”,当state里的数据变化时,组件会重新渲染,页面随之更新。

Vue 中的data是实例的 “响应式数据对象”,当data里的数据变化时,Vue 会自动更新对应的 DOM。

两者作用一致:让数据变化驱动页面自动更新,实现 “响应式” 的交互体验。

src/components文件夹放组件

src/components/test1.jsx文件放test1组件;src/components/test2.jsx文件放test2组件(组件写成js也是OK的)

test1.jsx文件写函数组件

  1. 组件首字母必须大写
  2. App.js文件中引入test1组件
  1.  './App.css';
    import Test1 from "./components/test1";

    function App() {
    return (
    <div className="App">
    <Test1></Test1>
    </div>
    );
    }

    export default App;
  1. state的编写需要结合Hook,使用 useState Hook 管理组件状态;useState 是 React 提供的状态 Hook,用于在函数组件中声明 “响应式状态”;objA:状态变量,初始值是一个对象{ a: 123 };setA:更新状态的函数,当调用 setA(newValue) 时,会修改 objA 的值,并触发组件重新渲染;普通变量的修改不会触发组件重新渲染,页面上显示的 b 值不会更新;而状态变量通过 setA 修改后,会自动重新渲染组件,页面同步更新
  1.  React, { useState } from "react" // 导入 React 核心库和 useState Hook
    //函数组件
    function Test1() {
    let [objA, setA] = useState({
    a: 123 // objA:状态变量
    })
    let b = "i am b"; // 普通的 JavaScript 变量
    return ( // 组件返回的 JSX 结构,定义了页面要显示的内容
    <div>
    <p>{objA.a}</p>
    <p>{b}</p>
    </div>
    )
    }
    export default Test1 // 将 Test1 组件设置为默认导出

test,jsx文件写class组件

  1. 继承React的Component,所以要引入React
  2. 写一个构造函数,构造函数是类组件初始化时第一个被调用的方法,用于初始化组件的状态(state)、绑定事件处理函数等;接收父组件传递给当前组件的属性(props),用于组件间的数据传递;super() 用于调用父类(React.Component)的构造函数,这是子类构造函数中必须执行的步骤,传递 props 作为参数,是为了在构造函数中能通过 this.props 访问父组件传递的属性;this.state 是类组件用于存储内部可变数据的对象,当 state 中的数据发生变化时,组件会自动重新渲染(响应式更新)。
  3. React 类组件必须实现 render() 方法(用于返回要渲染的 JSX 结构),否则组件无法正常渲染到页面
  4. App.js文件中也引入test2组件
  1.  './App.css';
    import Test1 from "./components/test1";
    import Test2 from "./components/test2";

    function App() {
    return (
    <div className="App">
    <Test1></Test1>
    <Test2></Test2>
    </div>
    );
    }

    export default App;

  1.  React from "react";
    class Test2 extends React.Component {
    constructor(props) {
    super(props);
    this.state = {
    a: 111,
    arr: [1, 23, 3]
    }
    }

    render() {
    return (
    <div>
    <p>{this.state.a}</p>
    </div>
    );
    }
    }

    export default Test2

state的特点:

  1. 直接修改数据是无效的,必须通过对应的方法修改 state 才能触发视图更新;在 React 中,无论是类组件的 this.state 还是函数组件的 useState 状态直接修改状态变量本身不会触发组件重新渲染
  •  useState 返回的 “更新函数”(如 setCount);类组件:使用 this.setState() 方法;
  1. 是通过 “状态更新方法” 来感知状态变化的,只有通过这些方法,React 才会触发组件重新渲染,进而更新页面视图。
  1. State 的修改是一个浅合并的过程,State 的修改是与原 state 对象合并的过程;当修改 state 时,React 会将新状态与原状态进行 “浅层次合并”(只更新状态中指定的属性,未被指定的属性会保留原状态,且仅合并第一层属性)。

错误的:

import React, { useState } from "react"
//函数组件
function Test1() {
let [objA, setA] = useState({
a: 123
})
let b = "i am b";
setTimeout(()=>{ // 错误的状态更新方式,必须通过 useState 返回的更新函数(如 setA)修改状态,直接修改状态变量 objA 不会触发组件重新渲染,页面也不会更新
objA.a=999
},1000)
return (
<div>
<p>{objA.a}</p>
<p>{b}</p>
</div>
)
}
export default Test1

import React from "react";
//class组件
class Test2 extends React.Component {
constructor(prop) {
super(prop);
this.state = {
a: 111,
arr: [1, 23, 3]
}
}
render() {
setTimeout(()=>{ // 错误的状态更新方式,在 React 类组件中,不能直接修改 this.state,这种操作不会触发组件重新渲染,页面也不会同步更新
this.state.a = 888
}, 1000)
return (
<div>
<p>{this.state.a}</p>
</div>
)
}
}
export default Test2

正确的:

import React, { useState } from "react" 

function Test1() {
const [objA, setA] = useState({
a: 123
})
const b = "i am b";

setTimeout(()=>{
// 通过 setA 函数更新状态,触发重新渲染;浅合并:prev 代表原状态对象,...prev 是 ES6 展开运算符,用于复制原状态的所有第一层属性;然后用 a: 999 覆盖原 a 属性
setA(prev => ({ ...prev, a: 999 }))
},1000)

return (
<div>
<p>{objA.a}</p>
<p>{b}</p>
</div>
)
}

export default Test1

import React from "react";
//class组件
class Test2 extends React.Component {
constructor(prop) {
super(prop);
this.state = {
a: 111, // 第一层属性,值
arr: [1, 23, 3], // 另一个第一层属性,数组
user: { name: "张三", age: 18 }, // 嵌套对象(深层属性),对象
}
}
render() {
setTimeout(()=>{
this.setState({ a: 888 }); // 通过 setState 修改状态;浅合并:只更新了 a 这个第一层属性,其他第一层属性(arr、user)完全保留原状态,没有被清空或替换
}, 1000)

return (
<div>
<p>{this.state.a}</p>
</div>
)
}
}
export default Test2

// 原状态:info: { city: "北京", zip: "100000" }
setA(prev => ({
info: { zip: "200000" } // 直接替换 info 对象(city 丢失),同样需要手动复制深层属性:info: { ...prev.info, zip: "200000" }
}));

// 原状态:user: { name: "张三", age: 18 }
this.setState({
user: { age: 19 } // 直接替换整个 user 对象(而非仅修改 age);合并后 user 会变成 { age: 19 }(name 属性丢失),因为 setState 只浅合并第一层,不会自动保留深层属性。必须手动复制深层属性:user: { ...prev.user, age: 19 }
});

数组的state修改:

render() {
setTimeout(() => {
let _arr = this.state.arr; // 创建新数组引用
_arr.push(1);
this.setState({
arr: _arr
})
}, 1000)
return (
<div>
<p>{this.state.a}</p>
<p>{this.state.arr[0]}</p>
<p>{this.state.arr[1]}</p>
<p>{this.state.arr[2]}</p>
<p>{this.state.arr[3]}</p>
</div>
)
}

对象的state修改:

render() {
setTimeout(() => {
let _obj = this.state.obj; // 创建新对象引用
_obj.obj1 = 777;
this.setState({
obj: _obj
})
}, 1000)
return (
<div>
<p>{this.state.a}</p>
<p>{this.state.obj.obj1}</p>
</div>
)
}

循环渲染和条件渲染

数组的所有值都渲染,需要用到循环渲染,jsx赋予html使用js结合的能力,可以直接在返回的jsx结构中使用循环,循环需要给一个key值,会让循环性能变高

// class组件的循环渲染
return (
<div>
<p>{this.state.a}</p>
<p>{this.state.obj.obj1}</p>
{
this.state.arr.map((item) => { // map可以将所有东西变成一个数组
return (
<div>
<h1>{item.title}</h1>
<p>{item.content}</p>
</div>
)
})
}
</div>
)

// 或者
render() {
let arr = []; // 创建新数组
this.state.arr.forEach((item) => {
arr.push(
<div key={item.title}>
<h1>{item.title}</h1>
<p>{item.content}</p>
</div>
);
});
}

// 或者
render() {
let arr = [];
this.state.arr.forEach((item) => { // 为每个 item 创建包含 title 和 content 的 JSX 结构
let _itemText = <div key={item.title}> 
<h1>{item.title}</h1>
<p>{item.content}</p>
</div>;
arr.push(_itemText);
});
}

// 或者
function createArrList() { // 定义一个新函数
let arr = [];
this.state.arr.forEach((item) => {
let _itemText = (
<div key={item.title}>
<h1>{item.title}</h1>
<p>{item.content}</p>
</div>
);
arr.push(_itemText);
});
return arr;
}

// 函数组件的条件渲染
import { react, useState } from "react"
function Test1() {
let [objA, setA] = useState({
a: 123
})
let [show, changeShow] = useState(true);
function showDiv(){ // 写一个函数
if(show){
return <div>123</div>
}
}
let b = "i am b";
setTimeout(() => {
setA({ a: 999 })
}, 1000)
return (
<div>
<p>{objA.a}</p>
<p>{b}</p>
{showDiv()}
</div>
)
}
export default Test1


// 或者
return(
<div>
{show?<div>123</div>:""};
</div>
)

// 或者
return( // && 第一个成立了才会执行后面的操作
<div>
{show && <div>123</div>};
</div>
)

// let [show, changeShow] = useState(0);面板的切换选择
function showTab(){ // 写一个函数
if(show == 0){
return <div>i am 0</div>
}else if(show == 1){
return <div>i am 1</div>
}else{
return <div>i am 2</div>
}
}
setTimeout(() => {
changeShow(1) // 1秒钟后0会变成1
},1000)

事件绑定

给用户操作界面,需要给元素绑定一些事件让用户进行操作时会有一些对应的响应

设置一个按钮,点击按钮,会将false变成true

import React, { useState } from "react" 
function Test1() {
let [objA, setA] = useState({
a: 123
})
let [show, changeShow] = useState(false);
function showTab() {
if (show) return <div>123</div>
}
function changeDiv(){ // 写一个函数,切换show的值
let _show = !show
changeShow(!show);
}
return ( // 绑定事件onClick与函数changeDiv
<div>
<p>{objA.a}</p>
{showTab()}
<button onClick={changeDiv}>{show ? '隐藏' : '显示'}</button>
</div>
)
}
export default Test1

// 绑定事件时如何传参
import { react, useState } from "react"
function Test1() {
let [objA, setA] = useState({
a: 123
})
let [show, changeShow] = useState(false);
function showTab() {
if (show) return <div>123</div>
}
function changeDiv(num) { // 事件处理函数,传参
console.log(num); // 打印传入的参数
let _show = !show;
changeShow(_show);
}
return ( // 通过 bind(this, 123) 传递参数 123 并绑定函数 changeDiv
<div>
<p>{objA.a}</p>
{showTab()}
<button onClick={changeDiv.bind(this, 123)}>{show ? '隐藏' : '显示'}</button>
</div>
)
}
export default Test1

//
function changeDiv(num, num2, e) { // 函数接收 num、num2和事件对象 e(会自动加上e)
e.stopPropagation(); // 阻止事件冒泡,阻止当前事件向父元素传播
let show = !show;
changeShow(show);
}

http://www.dtcms.com/a/614815.html

相关文章:

  • 前端无障碍开发标准,WCAG 2.2新特性
  • 人形机器人应用于职业教育与实训,以及素养课题设计与知识图谱动态更新
  • 人力资源网站怎么建设网站不想备案
  • 建设网站的文案范文深圳高端logo设计公司
  • 前端微前端架构设计,应用间通信 前端微前端架构设计:应用间通信的实践与挑战
  • 短讯 | 利用开源 Galaxy 平台简化临床细菌全基因组测序数据分析
  • 基于单片机的智慧校园自动打铃系统设计
  • 网站群建设管理规定做公司+网站建设价格
  • 搭建网站用服务器还是虚拟主机百度站长平台清退
  • 技术演进中的开发沉思-192 JavaScript: 发展历程(下篇)
  • 视频网站seo怎么做青海做网站的公司
  • 反编译使用易语言工具详细解析与实践指南
  • Android Navigation 组件(用于Fragment间的跳转)
  • 旅游做视频网站产品宣传网站开发
  • 常州做企业网站如何做好产品网络推广
  • 【具身智能】深入理解3D旋转:从欧拉角、万向锁到四元数与插值算法SLERP
  • 城市建设网站设计代码生成器在线
  • 浏览器中内嵌一个浏览器
  • 深圳网站建设推广方法赣州优化公司
  • 【模板】组合数(牛客)
  • 微信电影网站怎么做凡客网上商城
  • 《硬件学习杂记A》成为AI时代更全面的自己
  • VS2013编译C语言 | 如何在VS2013中编译C语言程序并解决常见问题
  • 怎么用自己电脑做网站服务器网址大全2345qiren
  • 建设网站需要学什么网上查公司怎么查
  • 企业网站模板cms南昌的网站推广公司
  • B.40.5.1-数据库基础与核心原理
  • 在razor页面上读写数据库(我的Blazor学习二)
  • sitemap怎么自动生成提交教程(sitemap新手教程)
  • 国内大型php网站建设合肥公司企业网站建设