文章目录
- 文章概述
- 1、React项目初始化和目录结构
- 2、react组件和jsx
- 3、React的事件绑定
-
- [3.1、 规则模式](#3.1、 规则模式)
- [3.2、 特别注意问题](#3.2、 特别注意问题)
- [3.3、 事件绑定其他操作](#3.3、 事件绑定其他操作)
- 4、React组件中的响应式数据
- ✒️总结
文章概述
本文面向有 Vue 基础的开发者,聚焦 React 项目级开发,不仅涵盖核心语法和组件机制,还深入探讨项目架构、性能优化及生态整合,帮助读者快速掌握 React 开发全流程。

相关内容
React 开发实战
基础核心
高阶技术
项目生态
React项目创建和目录结构
React组件和JSX
React的事件绑定
React中的响应式数据
条件渲染和列表循环
表单绑定
Props和组件间传值,插槽
React中的样式操作
生命周期
实战编写增删改查列表
函数组件和Hook
高阶组件
React性能问题和优化
React-router的使用
React中的全局状态管理
React中的路由权限控制
组件库等相关生态
1、React项目初始化和目录结构
- 使用官方的脚手架 通过npx create-react-app projectname能创建一个最基本的react项目
只做了react基本的搭建和构建,没有配上任何路由和状态管理。项目使用webpack构
- 使用一些市场上的集成脚手架 官方脚手架提供的项目模板非常简单,因此也有很多集成的脚手架
典型的比如umi。这一类脚手架创建出来的项目会集成好很多功能,比如路由,mock
1.1、通过官方的脚手架创建项目
bash
npx create-react-app 项目名称
或
npx create-react-app@latest 项目名称

1.2、项目目录结构(官方的脚手架)

- public文件夹放我们的静态资源
- src文件夹是我们编写核心代码的地方
- App.js是我们的根组件 (类似于Vue里面的Vue.vue)
- index.js(类似于Vue的mian.js把项目挂载到指定的dom节点)
- App.test.js对于App组件进行单元测试的文件
- setupTests.js单元测试的启动
- repotWebVitals.js这个是我们性能检测报告的相关js文件
1.3、两个核心库
- react:React核心库,提供react的个个功能。
- React-dom:提供一些dom操作方法用于把react创建出来的react对象挂载到真正的htmldom中,或者从htmldom中卸载。核心作用类似于vue的mount。
src下的index.js
js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
// ReactDOM就是把一个react组件从一个真正的dom里面卸载,或者渲染到真正的dom
const root = ReactDOM.createRoot(document.getElementById('root'));
// 渲染dom
root.render(
// React.StrictMode验证检查
<React.StrictMode>
<App />
</React.StrictMode>
);
//卸载dom
// setTimeout(()=>{
// root.unmount()
// },1000)
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
1.4、react项目组件关系

2、react组件和jsx
2.1、组件化开发,定义一个基本组件得有东西

2.2、React组件分类
- 函数组件
js
function Hello(){
return<div>hello</div>
}
- class组件
js
class hello extends React.Component{
render(){
return<div>hello</div>
}
}
demo
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
//jsx和react是互相独立的
function App() {
// 定义函数组件FnHello
function FnHello() {
return <div>FnHello</div>;
}
// 定义class组件ClassHello
class ClassHello extends React.Component {
constructor(props) {
super(props);
}
render() {
return <div>hello ClassHello</div>;
}
}
return (
<div className="App">
<FnHello></FnHello>
{/* 使用FnHello组件 */}
<ClassHello></ClassHello>
{/* 使用<ClassHello></ClassHello>组件 */}
</div>
);
}
export default App;

2.3、jsx的特点
- 直接js中混用:react项目利用babel做了对is的编译,所以我们是可以直接在js里写jsx的
- 写法接近js:j
- sx几乎和js一样,不同点就在于,可以更方便的写html在js里,写在js里的html最后会被编译成一个js对象,我们也可以用react自带createElement创建这个对象
react自带createElement创建
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
//jsx和react是互相独立的
function App() {
function FnHelloUnjsx() {
return React.createContext("div", [], "hello");
}
return (
<div className="App">
<FnHelloUnjsx></FnHelloUnjsx>
{/* 使用FnHelloUnjsx组件 */}
);
}
export default App;
2.4、编写jsx代码的本质

2.5、jsx里面渲染不同内容的区别
| 字符串、数字 | 直接渲染 |
| 方法 | 无法渲染 |
| 对象 | 只能渲染element对象 |
| 布尔值 | 不渲染任何内容 |
| 数组 | 把数组的每一项单独渲染 |
| Undefine,null | 不渲染任何内容 |
| 表达式 | 运行表达式 |
- 渲染字符串或者数字
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
//jsx和react是互相独立的
function App() {
return (
<div className="App">
{'hello,渲染字符串'}
{123}
</div>
);
}
export default App;

- 渲染对象
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
//jsx和react是互相独立的
function App() {
let obj={
a:1,
}
return (
<div className="App">
{obj}
</div>
);
}
export default App;
纯对象会报错

- 渲染element对象
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
//jsx和react是互相独立的
function App() {
// 定义函数组件FnHello
function FnHello() {
return <div>FnHello</div>;
}
let com1=<FnHello></FnHello>
return (
<div className="App">
{com1}
</div>
);
}
export default App;

- 渲染数组
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
//jsx和react是互相独立的
function App() {
let arr=[1,2,3]
return (
<div className="App">
{arr}
</div>
);
}
export default App;

- 渲染表达式
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
//jsx和react是互相独立的
function App() {
return (
<div className="App">
{1+2}
</div>
);
}
export default App;

3、React的事件绑定
3.1、 规则模式
- 类似于原生,on+方法名(首字母大写)
- 一定要赋值给事件一个方法
添加事件方式一
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
class App extends React.Component {
render(){
return <div className="App">
<div onClick={()=>{
console.log('类组件添加点击事件1')
}}>123</div>
</div>
}
}
export default App;
添加事件方式二
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
class App extends React.Component {
fn1(){
console.log('添加事件')
}
render(){
return <div className="App">
<div onClick={this.fn1}>123</div>
</div>
}
}
export default App;

3.2、 特别注意问题
- 不作处理的情况下,this会指向undefined
- 给到事件绑定的一定得是一个方法,不要直接调用方法调用方法只会在页面初次渲染指向方法
处理this方式一:给方法调用bind规定this
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
class App extends React.Component {
fn1(){
console.log(this)
}
render(){
return <div className="App">
<div onClick={this.fn1.bind(this)}>123</div>
</div>
}
}
export default App;
- 处理this方式一:使用匿名箭头函数或者方法本身写成箭头函数
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
class App extends React.Component {
fn1=()=>{
console.log(this)
}
render(){
return <div className="App">
<div onClick={()=>{
console.log(this)
}}>箭头函数修改指向1</div>
<div onClick={this.fn1}>箭头函数修改指向2</div>
</div>
}
}
export default App;

3.3、 事件绑定其他操作
- 传递参数 bind方法
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
class App extends React.Component {
fn1=(num1,num2)=>{
console.log(num1,num2)
}
render(){
return <div className="App">
{/* <div onClick={this.fn1.bind(this)}>123</div> */}
<div onClick={this.fn1.bind(this,1,2)}>通过bind传递参数</div>
</div>
}
}
export default App;

- 获取事件对象
这里的事件对象并不是原生的事件对象,而是合成的事件对象,原生的在该合成对象下的nativeEvent属性下面
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
class App extends React.Component {
// 无传参第一个参数就是我们的事件对象
fn1=(e)=>{
console.log('无参数默认第一个就是我们的事件对象',e)
}
// 有传参最后一个使我们的事件对象
fn2=(txt1,txt2,e)=>{
console.log('有参数默认最有一个就是我们的事件对象',e)
}
render(){
return <div className="App">
{/* <div onClick={this.fn1.bind(this)}>123</div> */}
<div onClick={this.fn1.bind(this)}>无传递事件对象</div>
<div onClick={this.fn2.bind(this,'参数1','参数二')}>有传递事件对象</div>
</div>
}
}
export default App;

- 阻止默认行为,冒泡等
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
class App extends React.Component {
// 无传参第一个参数就是我们的事件对象
fn1=(e)=>{
// event.stopPropagation();//阻止事件冒泡
// event.preventDefault();//阻止默认行为
// 和原生保持一致
console.log('阻止冒泡',e.stopPropagation(),'阻止默认行为',e.preventDefault(),)
}
render(){
return <div className="App">
<div onClick={this.fn1.bind(this)}>无传递事件对象</div>
</div>
}
}
export default App;
4、React组件中的响应式数据
4.1、类组件响应式数据的定义
响应式数据定义在类的state属性中
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
class App extends React.Component {
// 旧写法
// constructor(props){
// super(props)
// this.state={
// // 定义响应式数据
// }
// }
// es7新写法
state={
a:0,//定义响应式数据
}
render(){
return <div className="App">
{this.state.a}
</div>
}
}
export default App;
4.2、react响应式体系的原理
- react不能像vue-样直接修改触发更新
- react修改能改值,但无法触发更新,因为react没有像vue一样监听get和set,而是在调用setState的时候调用react的更新操作
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
class App extends React.Component {
// es7新写法
state = {
a: 0, //定义响应式数据
};
// setState更新数据
addA=()=>{
// 方式一
// this.setState({
// a:++this.state.a
// })
// 方式二
this.setState(()=>{
return{
a:++this.state.a
}
})
console.log(this.state.a)
}
render() {
return (
<div className="App">
{this.state.a}
<button onClick={this.addA}>a+1</button>
</div>
);
}
}
export default App;
4.3、react工作流程图解

关键点:
- 通过浅合并来修改数据
- 调用setState方法会触发更新,修改start并不会触发更新
4.4、setState方法的修改是异步的
所以如果我们要获取修改后的值,需要在setState的第二个参数里获取
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
class App extends React.Component {
state = {
a: 0, //定义响应式数据
};
// setState更新数据
addA=()=>{
// 如果我们要获取修改后的值,需要在setState的第二个参数里获取
this.setState(()=>{
return{
a:++this.state.a
}
},()=>{
//在这里面才能获取到更新后的数据
console.log(this.state.a)
})
}
render() {
return (
<div className="App">
{this.state.a}
<button onClick={this.addA}>a+1</button>
</div>
);
}
}
export default App;
4.4、setState的一些特性
- setState方法多次修改,会合并为一次,统一更新
- setState返回会触发更新,不管你是否有修改,这造成了一个问题,重复修改为相同的值也会让组件更新。
- 一定不要在render里直接setState
使用 React.PureComponent解决修改为相同的值也会让组件更新
js
import logo from "./logo.svg";
import "./App.css";
import React from "react";
class App extends React.PureComponent {
// es7新写法
state = {
a: 0, //定义响应式数据
};
// setState更新数据
addA=()=>{
// 如果我们要获取修改后的值,需要在setState的第二个参数里获取
this.setState(()=>{
return{
a:1
}
},()=>{
//在这里面才能获取到更新后的数据
console.log(this.state.a)
})
}
render() {
console.log('reader')
return (
<div className="App">
{this.state.a}
<button onClick={this.addA}>a+1</button>
</div>
);
}
}
export default App;
4.5、PureComponent下对于对象和数组的修改
因为PureComponent会根据state是否改变来决定是否更新,而我们对于对象数组,这样的引用类型判断他是否改变的原理是看他的内存地址,而不是内容,所以我们PureComponent下修改对象和数组,一定要赋予一个新对象,所以一般我们不直接操作原对象,而是先拷贝一份,在进行操作
✒️总结
如果这篇【文章】有帮助到你💖,希望可以给我点个赞👍,创作不易,如果有对前端端或者对python感兴趣的朋友,请多多关注💖💖💖,咱们一起探讨和努力!!!
👨🔧 个人主页 : 前端初见