JavaScript基础课程二十三、前端框架实战(React 基础)

JavaScript前端核心进阶课

本课作为React框架入门核心课,聚焦React基础语法与实战,从组件化、JSX、Hooks到项目搭建,完整覆盖React入门必备知识点。React以组件化为核心,通过虚拟DOM提升渲染效率,单向数据流保证代码可维护性,Hooks则简化了函数式组件的状态与副作用管理,是当前前端主流框架之一。课程通过单词管理实战案例,串联起组件创建、Props传参、useState响应式、useEffect副作用等核心内容,结合Vite工程化快速搭建项目,帮助建立React组件化开发思维。掌握本课内容,不仅能快速上手React基础开发,还能理解React与Vue3的差异,拓宽前端技术栈,为后续React进阶(路由、状态管理)和企业级项目开发奠定坚实基础。

一、课程学习目的

  1. 理解React框架的核心理念,掌握组件化开发虚拟DOM单向数据流三大核心特性。

  2. 掌握React基础语法,包括JSX语法、组件定义、Props传参、State状态管理。

  3. 熟练使用React Hooks(useState、useEffect),实现响应式数据与副作用管理。

  4. 学会React组件的创建、渲染、嵌套与通信,搭建简单的React页面。

  5. 结合Vite工程化搭建React项目,了解React与Vue3的差异,拓宽前端技术视野。

  6. 建立React组件化开发思维,为后续React进阶与企业级项目开发奠定基础。

二、核心知识点讲解

1. React 框架基础认知

React是由Facebook开发的开源前端框架,主打组件化声明式渲染,核心是将页面拆分为独立、可复用的组件,通过状态驱动视图更新。

核心优势:组件复用性强、虚拟DOM提升渲染效率、单向数据流使代码可预测、生态完善(适配移动端、后端渲染等)。

React 18为当前稳定版本,主推函数式组件+Hooks,替代传统类组件,语法更简洁、上手成本更低。

2. JSX 核心语法

JSX是React的模板语法,将HTML与JavaScript融合,允许在JavaScript中编写类似HTML的代码,最终会被编译为普通JavaScript执行。

核心规则:

  • 标签必须闭合(如

    、),禁止遗漏闭合标签。

  • className 替代HTML中的class(避免与JavaScript的class关键字冲突)。

  • 内联样式需用对象形式编写,如style={{ color: 'red', fontSize: '16px' }}。

  • JavaScript表达式需用{}包裹,如{变量名}、{函数调用()}。

  • 只能有一个根节点,多个标签需用

    、(简写<></>)包裹。

3. React 组件基础

React组件是页面的最小组成单元,分为函数式组件(推荐)和类组件,函数式组件配合Hooks实现响应式。

  • 函数式组件:本质是普通JavaScript函数,返回JSX模板,接收Props参数传递数据。

  • Props:组件间通信的核心,用于父组件向子组件传递数据,Props只读不可修改。

  • State:组件内部的响应式数据,修改State会触发组件重新渲染,需通过useState Hook定义。

4. React Hooks 基础(useState、useEffect)

Hooks是React 16.8推出的特性,允许函数式组件拥有状态和副作用,无需编写类组件。

  • useState:定义组件内部响应式状态,返回"状态变量+修改状态的函数",如const [count, setCount] = useState(0)。

  • useEffect:处理组件副作用(如数据请求、DOM操作、定时器),相当于类组件的生命周期钩子,可控制执行时机。

5. Vite 搭建 React 项目流程

依托前课npm+Vite知识,直接创建React模板项目,内置React环境和Hooks支持,无需手动配置,开箱即用,快速上手开发。

三、示例程序

示例1:React 函数式组件基础(单词展示组件)

jsx 复制代码
// src/components/WordItem.jsx(子组件)
// 子组件:接收Props传递的单词数据
function WordItem(props) {
  // 接收父组件传递的props参数
  const { en, cn } = props;

  return (
    <div className="word-item">
      <span>{en} - {cn}</span>
    </div>
  );
}

export default WordItem;

示例2:useState + useEffect 实战(单词管理器)

jsx 复制代码
// src/App.jsx(主组件)
import { useState, useEffect } from 'react';
import WordItem from './components/WordItem';

function App() {
  // 1. useState定义响应式状态:单词列表、输入框内容
  const [wordList, setWordList] = useState([
    { en: 'apple', cn: '苹果' },
    { en: 'banana', cn: '香蕉' }
  ]);
  const [inputEn, setInputEn] = useState('');
  const [inputCn, setInputCn] = useState('');

  // 2. 定义添加单词方法
  const addWord = () => {
    if (!inputEn || !inputCn) return;
    // 修改状态(不可直接修改原数组,需返回新数组)
    setWordList([...wordList, { en: inputEn, cn: inputCn }]);
    // 清空输入框
    setInputEn('');
    setInputCn('');
  };

  // 3. useEffect处理副作用:页面加载时打印提示
  useEffect(() => {
    console.log('页面初始化完成,单词列表已加载');
    // 依赖项为空数组,仅执行一次(相当于页面加载完成)
  }, []);

  return (
    <div className="app">
      <h1>React 单词管理器</h1>
      <div className="input-box">
        <input
          type="text"
          placeholder="请输入英文单词"
          value={inputEn}
          // 绑定输入事件,修改inputEn状态(单向数据流)
          onChange={(e) => setInputEn(e.target.value)}
        />
        <input
          type="text"
          placeholder="请输入中文释义"
          value={inputCn}
          onChange={(e) => setInputCn(e.target.value)}
        />
        <button onClick={addWord}>添加单词</button>
      </div>
      <div className="word-list">
        {/* 循环渲染子组件,传递props参数 */}
        {wordList.map((item, index) => (
          <WordItem key={index} en={item.en} cn={item.cn} />
        ))}
      </div>
    </div>
  );
}

export default App;

示例3:Vite 创建 React 项目命令

bash 复制代码
# 1. 创建Vite项目
npm create vite@latest

# 2. 配置项(按提示选择)
# 项目名称:react-word-project
# 框架选择:React
# 语言选择:JavaScript

# 3. 进入项目、安装依赖、启动项目
cd react-word-project
npm install
npm run dev

示例4:main.jsx(项目入口)

jsx 复制代码
// src/main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './index.css';

// 挂载React组件到页面
ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

四、掌握技巧与方法

  1. JSX语法需严格遵循React规则,标签闭合、className、内联样式格式不可出错,否则会导致渲染失败。

  2. 组件拆分遵循"单一职责",一个组件只做一件事,复杂组件拆分为多个子组件,提升复用性。

  3. useState修改状态时,不可直接修改原状态(如wordList.push()),需返回新的状态值(如[...wordList, newItem])。

  4. Props是只读的,子组件不可修改父组件传递的Props,如需修改,需通过父组件传递的方法修改。

  5. useEffect依赖项控制执行时机:空数组仅执行一次,依赖特定变量则变量变化时执行,无依赖项则每次渲染都执行。

  6. 调试React组件时,可使用React Developer Tools插件,查看组件结构、状态和Props。

  7. 区分React与Vue3:React是单向数据流,Vue3支持双向绑定;React依赖Hooks实现响应式,Vue3依赖ref/reactive。

五、课后作业

基础作业

  1. 用Vite创建React项目,启动并运行默认页面,熟悉React项目结构(src、App.jsx、main.jsx)。

  2. 编写一个简单的函数式组件,使用useState定义一个响应式变量,通过按钮修改该变量并渲染到页面。

  3. 创建父组件与子组件,通过Props实现父组件向子组件传递数据并渲染。

进阶作业

  1. 完善单词管理器,添加删除单词功能,通过useState修改单词列表状态。

  2. 使用useEffect实现"页面加载时请求模拟数据",并渲染到页面。

  3. 实现组件嵌套,拆分输入组件、列表组件、单词项组件,提升代码复用性。

实战作业

  1. 搭建React单词管理系统,整合JSX语法、组件拆分、Props传参、useState、useEffect,实现单词增删、数据渲染、副作用处理,纳入Git版本管理,符合代码规范。

上一课:Vue3 核心进阶(路由与状态管理)实战作业代码

完整实战代码

一、项目结构(规范工程化结构)

Plain 复制代码
vue3-router-pinia-demo/
├── index.html
├── package.json
└── src/
    ├── main.js          # 全局注册路由、Pinia
    ├── App.vue          # 路由出口、导航栏
    ├── router/          # 路由配置
    │   └── index.js
    ├── stores/          # Pinia仓库
    │   └── wordStore.js
    └── views/           # 页面组件
        ├── Home.vue     # 首页
        ├── WordList.vue # 单词列表页
        └── WordDetail.vue # 单词详情页

二、package.json(依赖配置)

Plain 复制代码
{
  "name": "vue3-router-pinia-demo",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "vite build",
    "preview": "vite preview"
  },
  "devDependencies": {
    "vite": "^5.0.0",
    "vue": "^3.4.0"
  },
  "dependencies": {
    "pinia": "^2.1.7",
    "vue-router": "^4.3.0"
  }
}

三、src/router/index.js(路由配置)

Plain 复制代码
import { createRouter, createWebHistory } from 'vue-router'
// 导入页面组件
import Home from '../views/Home.vue'
import WordList from '../views/WordList.vue'
import WordDetail from '../views/WordDetail.vue'

// 路由规则:path(路径)→ component(对应组件)
const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/word-list',
    name: 'WordList',
    component: WordList
  },
  // 动态路由传参::word 为参数名
  {
    path: '/word-detail/:word',
    name: 'WordDetail',
    component: WordDetail
  }
]

// 创建路由实例
const router = createRouter({
  history: createWebHistory(), // 历史模式(无#)
  routes // 挂载路由规则
})

export default router

四、src/stores/wordStore.js(Pinia仓库)

Plain 复制代码
import { defineStore } from 'pinia'

// 定义仓库:第一个参数是仓库名(唯一),第二个参数是配置
export const useWordStore = defineStore('word', {
  // 存储共享数据
  state: () => ({
    wordList: [
      { en: 'apple', cn: '苹果' },
      { en: 'banana', cn: '香蕉' },
      { en: 'orange', cn: '橙子' }
    ]
  }),
  // 定义修改数据的方法(规范写法)
  actions: {
    // 添加单词
    addWord(word) {
      this.wordList.push(word)
    },
    // 删除单词
    delWord(index) {
      this.wordList.splice(index, 1)
    }
  }
})

五、src/main.js(全局注册)

Plain 复制代码
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 导入路由
import { createPinia } from 'pinia' // 导入Pinia

const app = createApp(App)
app.use(router) // 注册路由
app.use(createPinia()) // 注册Pinia
app.mount('#app') // 挂载到页面

六、src/App.vue(路由出口与导航)

Plain 复制代码
<template>
  <div class="app">
    <!-- 路由导航栏 -->
    <nav class="nav">
      <router-link to="/">首页</router-link>
      <router-link to="/word-list">单词列表</router-link>
    </nav>
    <!-- 路由出口:页面组件会渲染到这里 -->
    <router-view class="content"></router-view>
  </div>
</template>

<style scoped>
.nav {
  padding: 20px;
  background: #f5f5f5;
}
.nav router-link {
  margin: 0 10px;
  text-decoration: none;
  color: #333;
}
.nav router-link.active {
  color: #42b983;
  font-weight: bold;
}
.content {
  padding: 20px;
  max-width: 600px;
  margin: 0 auto;
}
</style>

七、src/views/Home.vue(首页)

Plain 复制代码
<template>
  <div class="home">
    <h2>Vue3 路由与Pinia实战</h2>
    <p>当前单词库总数:{{ wordStore.wordList.length }}</p>
    <button @click="$router.push('/word-list')">进入单词列表</button>
  </div>
</template>

<script setup>
// 导入Pinia仓库
import { useWordStore } from '../stores/wordStore'
const wordStore = useWordStore()
</script>

八、src/views/WordList.vue(单词列表页)

Plain 复制代码
<template>
  <div class="word-list">
    <h2>单词列表</h2>
    <div class="input-box">
      <input v-model="inputEn" placeholder="英文单词" />
      <input v-model="inputCn" placeholder="中文释义" />
      <button @click="addWord">添加</button>
    </div>
    <ul>
      <li v-for="(item, index) in wordStore.wordList" :key="index">
        {{ item.en }} - {{ item.cn }}
        <button @click="delWord(index)">删除</button>
        <button @click="toDetail(item.en)">详情</button>
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from 'vue'
import { useWordStore } from '../stores/wordStore'
import { useRouter } from 'vue-router'

const wordStore = useWordStore()
const router = useRouter()
const inputEn = ref('')
const inputCn = ref('')

// 添加单词(调用Pinia的actions方法)
const addWord = () => {
  if (!inputEn.value || !inputCn.value) return
  wordStore.addWord({ en: inputEn.value, cn: inputCn.value })
  inputEn.value = ''
  inputCn.value = ''
}

// 删除单词
const delWord = (index) => {
  wordStore.delWord(index)
}

// 路由跳转传参
const toDetail = (word) => {
  router.push(`/word-detail/${word}`)
}
</script>

<style scoped>
.input-box { margin: 20px 0; }
input { padding: 8px; margin-right: 8px; }
button { padding: 8px 12px; cursor: pointer; background: #42b983; color: #fff; border: none; border-radius: 4px; margin-right: 8px; }
li { margin: 10px 0; padding: 10px; background: #f9f9f9; border-radius: 4px; }
</style>

九、src/views/WordDetail.vue(单词详情页)

Plain 复制代码
<template>
  <div class="word-detail">
    <h2>单词详情</h2>
    <div v-if="currentWord" class="detail-box">
      <p>英文:{{ currentWord.en }}</p>
      <p>中文:{{ currentWord.cn }}</p>
    </div>
    <div v-else>单词不存在</div>
    <button @click="$router.back()">返回列表</button>
  </div>
</template>

<script setup>
import { useWordStore } from '../stores/wordStore'
import { useRoute } from 'vue-router'

const wordStore = useWordStore()
// 获取路由参数
const route = useRoute()
// 从路由参数中获取单词
const word = route.params.word
// 查找对应的单词信息
const currentWord = wordStore.wordList.find(item => item.en === word)
</script>

十、运行命令

Plain 复制代码
# 1. 安装依赖(首次运行)
npm install

# 2. 启动开发服务器
npm run dev

# 3. 打包项目(上线用)
npm run build

代码功能说明

本实战代码基于Vite+Vue3,整合Vue Router4与Pinia,实现多页面单词管理系统。项目配置3个路由(首页、单词列表、单词详情),通过路由实现页面跳转与动态传参;用Pinia定义全局状态仓库,统一管理单词数据,实现跨组件数据共享;列表页可添加、删除单词,详情页通过路由参数接收并展示单词信息,首页展示仓库中的单词总数。代码结构规范、注释完整,涵盖路由配置、Pinia仓库定义、组件中使用路由与状态管理等核心知识点,直观演示Vue3进阶开发流程,巩固路由与状态管理用法,适配课程实战要求。

注意事项

  • 必须先安装Vue Router和Pinia依赖(npm i vue-router pinia),否则会报模块引入错误。

  • 路由配置需正确对应组件路径,动态路由传参格式为"/:参数名",接收参数需用useRoute()。

  • Pinia仓库需用defineStore定义,组件中使用需先通过useStore()获取实例,不可直接修改state。

  • main.js中必须注册Vue Router和Pinia(app.use(router).use(createPinia())),否则无法使用。

  • 路由跳转优先使用router.push(),页面展示需用,导航栏用。

  • Pinia中修改数据建议写在actions中,规范统一,便于维护和调试。

  • 动态路由参数不可为空,跳转时需确保参数有效,避免页面报错。

  • 项目运行命令:npm install → npm run dev,确保依赖安装完整。

作业验收标准

  1. 项目可正常启动,路由导航切换流畅,无控制台报错。

  2. Pinia仓库功能正常,添加、删除单词后,所有组件数据同步更新。

  3. 动态路由传参有效,详情页能正确接收并展示对应单词信息。

  4. 代码结构规范,路由配置、Pinia仓库定义、组件使用符合课程知识点。

  5. 页面交互正常,按钮点击、路由跳转、数据修改无异常。

相关推荐
RFCEO4 天前
JavaScript基础课程十九、前端工程化基础(npm + Vite)
package.json·javascript前端课程·前端工程化npm基础命令大全·vite创建原生js项目教程·npm安装与卸载依赖包方法·vite启动与打包项目命令·es6模块化在vite中使用