React 开发实战全攻略:从基础到项目实战(面向 Vue 开发者)

文章目录


文章概述

本文面向有 Vue 基础的开发者,聚焦 React 项目级开发,不仅涵盖核心语法和组件机制,还深入探讨项目架构、性能优化及生态整合,帮助读者快速掌握 React 开发全流程。

相关内容

React 开发实战
基础核心
高阶技术
项目生态
React项目创建和目录结构
React组件和JSX
React的事件绑定
React中的响应式数据
条件渲染和列表循环
表单绑定
Props和组件间传值,插槽
React中的样式操作
生命周期
实战编写增删改查列表
函数组件和Hook
高阶组件
React性能问题和优化
React-router的使用
React中的全局状态管理
React中的路由权限控制
组件库等相关生态

1、React项目初始化和目录结构

  1. 使用官方的脚手架 通过npx create-react-app projectname能创建一个最基本的react项目

    只做了react基本的搭建和构建,没有配上任何路由和状态管理。项目使用webpack构

  2. 使用一些市场上的集成脚手架 官方脚手架提供的项目模板非常简单,因此也有很多集成的脚手架

    典型的比如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、两个核心库

  1. react:React核心库,提供react的个个功能。
  2. 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组件分类

  1. 函数组件
js 复制代码
function Hello(){
    return<div>hello</div>
}
  1. 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 不渲染任何内容
表达式 运行表达式
  1. 渲染字符串或者数字
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;
  1. 渲染对象
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;

纯对象会报错

  1. 渲染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;
  1. 渲染数组
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;
  1. 渲染表达式
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、 规则模式

  1. 类似于原生,on+方法名(首字母大写)
  2. 一定要赋值给事件一个方法

添加事件方式一

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、 特别注意问题

  1. 不作处理的情况下,this会指向undefined
  2. 给到事件绑定的一定得是一个方法,不要直接调用方法调用方法只会在页面初次渲染指向方法

处理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、 事件绑定其他操作

  1. 传递参数 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;
  1. 获取事件对象

这里的事件对象并不是原生的事件对象,而是合成的事件对象,原生的在该合成对象下的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;
  1. 阻止默认行为,冒泡等
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响应式体系的原理

  1. react不能像vue-样直接修改触发更新
  2. 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工作流程图解

关键点:

  1. 通过浅合并来修改数据
  2. 调用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的一些特性

  1. setState方法多次修改,会合并为一次,统一更新
  2. setState返回会触发更新,不管你是否有修改,这造成了一个问题,重复修改为相同的值也会让组件更新。
  3. 一定不要在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感兴趣的朋友,请多多关注💖💖💖,咱们一起探讨和努力!!!

👨‍🔧 个人主页 : 前端初见

相关推荐
右耳朵猫AI1 小时前
React技术周刊 2026年第14周
前端·react.js·前端框架
csj501 小时前
前端基础之《React(8)—webpack简介-其他配置》
前端·react.js
lichenyang4531 小时前
从零理解微前端:基于 React + Vite + qiankun 的子应用切换 Demo
前端·react.js·状态模式
threelab1 小时前
Three.js 极光效果着色器 | 三维可视化 / AI 提示词
javascript·人工智能·着色器
天天进步20152 小时前
魔音漫创源码解析:性能优化: Electron 环境下的图片管理与文件系统协议处理优化
javascript·性能优化·electron
小妖6662 小时前
js 实现python的SortedList有序集合
java·javascript·python
kyriewen10 小时前
程序员连夜带团队跑路,省了23万:这AI太贵,真的用不起了
前端·javascript·openai
我叫黑大帅12 小时前
为什么需要 @types/react?解决“无法找到模块 react 的声明文件”报错
前端·javascript·面试
之歆13 小时前
DAY_21JavaScript 深度解析:数组(Array)与函数(Function)(一)
前端·javascript