前端框架---React

React 是由 Meta(原 Facebook)开发并维护的声明式、组件化 前端库(常被称作框架),核心定位是「构建用户界面」,凭借「虚拟DOM、单向数据流、组件化」三大核心特性,成为当前最主流的前端开发方案之一。
React快速学习---中文文档

一、React 核心基础

1. 核心定位与设计理念

React 不是「全栈框架」,而是专注于 UI 层的库,核心设计理念:

  • 声明式编程:只需描述「UI 应该是什么样」,而非「如何一步步构建 UI」(对比命令式编程),React 自动处理 DOM 更新;
  • 组件化:将 UI 拆分为独立、可复用的「组件」,每个组件负责一部分界面,降低复杂度;
  • 单向数据流:数据从父组件流向子组件,状态变更可追溯,避免数据混乱;
  • 虚拟DOM(VDOM):内存中维护一份 DOM 抽象层,通过「diff 算法」对比新旧 VDOM,仅更新变化的部分,提升渲染性能。

2. 环境搭建(两种主流方式)

方式1:Create React App(CRA,官方脚手架,适合新手)
bash 复制代码
# 安装(需Node.js 14+)
npx create-react-app my-react-app
# 启动项目
cd my-react-app
npm start
方式2:Vite(新一代构建工具,速度更快,推荐生产使用)
bash 复制代码
# 创建Vite+React项目
npm create vite@latest my-react-app -- --template react
# 安装依赖并启动
cd my-react-app
npm install
npm run dev

3. JSX:React 的核心语法糖

JSX 是「JavaScript XML」的缩写,不是 HTML/JS,而是 React 提供的语法糖,最终会被 @babel/plugin-transform-react-jsx 编译为 React.createElement() 调用。

核心规则(必记)
  1. 根节点:JSX 必须有唯一根节点(或用 <React.Fragment>/<> </> 空Fragment 避免多余 DOM);
  2. 属性命名:采用「小驼峰」(如 className 代替 HTML 的 classhtmlFor 代替 for);
  3. 表达式插入:用 {} 包裹 JS 表达式(变量、三元运算、函数调用等,不能放语句如 if/for);
  4. 注释写法:{/* 这是JSX注释 */}
  5. 样式:行内样式需传对象(style={``{ color: 'red', fontSize: '16px' }})。
示例代码
jsx 复制代码
import React from 'react';

const UserCard = () => {
  const name = '张三';
  const isVip = true;
  const getAge = () => 20;

  return (
    <div className="user-card">
      {/* 表达式插入 */}
      <h2>姓名:{name}</h2>
      <p>年龄:{getAge()}</p>
      {/* 条件渲染 */}
      <p>会员状态:{isVip ? 'VIP用户' : '普通用户'}</p>
      {/* 行内样式 */}
      <button style={{ backgroundColor: 'blue', color: 'white' }}>
        点击
      </button>
    </div>
  );
};

export default UserCard;

4. 组件:React 的基本单元

React 组件分为「函数组件」(现代主流)和「类组件」(传统方式,逐渐淘汰),核心是「复用 UI 逻辑」。

(1)函数组件(推荐)

无状态组件 → 引入 Hooks 后支持状态,简洁、易维护:

jsx 复制代码
// 无参数基础组件
const Hello = () => {
  return <h1>Hello React</h1>;
};

// 带Props的组件
const Greeting = (props) => {
  // 解构Props,简化写法
  const { name, age } = props;
  return <p>你好{name},年龄{age}</p>;
};

// 使用组件
const App = () => {
  return (
    <div>
      <Hello />
      <Greeting name="李四" age={22} />
    </div>
  );
};
(2)类组件(兼容旧代码)

需继承 React.Component,通过 this 访问 props/state:

jsx 复制代码
import React, { Component } from 'react';

class Counter extends Component {
  // 初始化状态
  state = { count: 0 };

  // 事件处理(需绑定this,或用箭头函数)
  increment = () => {
    // setState是异步的,更新状态必须用setState,不能直接修改this.state
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>计数:{this.state.count}</p>
        <button onClick={this.increment}>+1</button>
      </div>
    );
  }
}

5. Props:组件的「输入参数」

Props(Properties)是父组件向子组件传递数据的唯一方式,核心特性:

  • 只读性:子组件不能修改 Props(单向数据流);
  • 默认Props :通过 defaultProps 或函数默认参数设置;
  • Props校验 :用 prop-types 库校验参数类型,避免传参错误。
示例:Props 校验与默认值
jsx 复制代码
import React from 'react';
import PropTypes from 'prop-types';

const Product = ({ name, price, stock = 0 }) => {
  return (
    <div>
      <h3>{name}</h3>
      <p>价格:{price}元</p>
      <p>库存:{stock}件</p>
    </div>
  );
};

// Props 校验
Product.propTypes = {
  name: PropTypes.string.isRequired, // 必传字符串
  price: PropTypes.number.isRequired, // 必传数字
  stock: PropTypes.number // 可选数字
};

// 默认Props(也可直接用函数默认参数)
Product.defaultProps = {
  stock: 0
};

6. State:组件的「内部状态」

State 是组件自身可修改的数据,触发组件重新渲染,核心规则:

  • 不可直接修改 :类组件需用 this.setState(),函数组件需用 useState 返回的更新函数;
  • 异步更新:setState/useState 更新函数是异步的,依赖当前状态更新时需传「函数形式」;
  • 函数组件 State :通过 useState Hook 实现,支持多状态拆分。
示例:函数组件 State(主流写法)
jsx 复制代码
import { useState } from 'react';

const Counter = () => {
  // 声明状态:[状态值, 更新函数]
  const [count, setCount] = useState(0);
  const [message, setMessage] = useState('初始消息');

  // 依赖当前状态的更新(传函数)
  const increment = () => {
    setCount(prevCount => prevCount + 1); // 推荐:用前一次状态计算
  };

  return (
    <div>
      <p>计数:{count}</p>
      <button onClick={increment}>+1</button>
      <input
        value={message}
        onChange={(e) => setMessage(e.target.value)}
        placeholder="输入消息"
      />
    </div>
  );
};

7. 生命周期(类组件)与副作用(函数组件)

(1)类组件生命周期(三大阶段)
阶段 核心钩子函数 作用
挂载阶段 constructor → render → componentDidMount 初始化状态 → 渲染DOM → DOM挂载完成(请求数据)
更新阶段 shouldComponentUpdate → render → componentDidUpdate 判断是否更新 → 重新渲染 → 更新完成(更新DOM)
卸载阶段 componentWillUnmount 组件卸载前(清理定时器、取消请求)
(2)函数组件:useEffect 替代生命周期

useEffect 是处理「副作用」(数据请求、DOM操作、定时器等)的核心 Hook,语法:

jsx 复制代码
import { useState, useEffect } from 'react';

const DataFetch = () => {
  const [data, setData] = useState(null);

  // 模拟componentDidMount(仅挂载时执行)
  useEffect(() => {
    // 副作用逻辑:请求数据
    fetch('https://api.example.com/data')
      .then(res => res.json())
      .then(data => setData(data));

    // 清理函数(模拟componentWillUnmount)
    return () => {
      // 取消请求、清理定时器等
      console.log('组件卸载,清理副作用');
    };
  }, []); // 依赖数组为空:仅执行一次

  // 依赖count的副作用(count变化时执行)
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `计数:${count}`;
  }, [count]); // 依赖数组:仅count变化时执行

  return <div>{data ? JSON.stringify(data) : '加载中...'}</div>;
};

8. 事件处理、条件渲染、列表渲染

(1)事件处理

React 事件是「合成事件」(跨浏览器兼容),命名为小驼峰(如 onClick),注意类组件 this 绑定问题:

jsx 复制代码
// 函数组件事件(简单)
const Button = () => {
  const handleClick = (e) => {
    e.preventDefault(); // 阻止默认行为
    console.log('按钮点击');
  };
  return <button onClick={handleClick}>点击我</button>;
};
(2)条件渲染

通过 JS 逻辑控制 UI 显示/隐藏,常用方式:

jsx 复制代码
const Auth = ({ isLogin }) => {
  // 方式1:if-else
  if (isLogin) return <p>已登录</p>;
  return <button>登录</button>;

  // 方式2:三元表达式
  // return isLogin ? <p>已登录</p> : <button>登录</button>;

  // 方式3:&&运算符(仅满足条件时渲染)
  // return isLogin && <p>已登录</p>;
};
(3)列表渲染

map 遍历数组,必须加 key(唯一标识,优先用ID,不用index):

jsx 复制代码
const TodoList = () => {
  const todos = [
    { id: 1, text: '学习React' },
    { id: 2, text: '写代码' },
    { id: 3, text: '总结知识点' }
  ];

  return (
    <ul>
      {todos.map(todo => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  );
};

9. 表单处理

分为「受控组件」(推荐)和「非受控组件」:

(1)受控组件(值由State控制)
jsx 复制代码
import { useState } from 'react';

const Form = () => {
  const [formData, setFormData] = useState({
    username: '',
    gender: 'male',
    agree: false
  });

  // 统一处理表单变更
  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;
    setFormData(prev => ({
      ...prev,
      [name]: type === 'checkbox' ? checked : value
    }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('表单数据:', formData);
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* 输入框 */}
      <input
        type="text"
        name="username"
        value={formData.username}
        onChange={handleChange}
        placeholder="用户名"
      />
      {/* 单选框 */}
      <label>
        <input
          type="radio"
          name="gender"
          value="male"
          checked={formData.gender === 'male'}
          onChange={handleChange}
        />
        男
      </label>
      <label>
        <input
          type="radio"
          name="gender"
          value="female"
          checked={formData.gender === 'female'}
          onChange={handleChange}
        />
        女
      </label>
      {/* 复选框 */}
      <label>
        <input
          type="checkbox"
          name="agree"
          checked={formData.agree}
          onChange={handleChange}
        />
        同意协议
      </label>
      <button type="submit">提交</button>
    </form>
  );
};
(2)非受控组件(用Ref获取值)

适合简单场景(如文件上传):

jsx 复制代码
import { useRef } from 'react';

const UncontrolledForm = () => {
  const inputRef = useRef(null);

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('输入值:', inputRef.current.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" ref={inputRef} />
      <button type="submit">提交</button>
    </form>
  );
};

二、React 进阶特性

1. Hooks 全解析(React 16.8+ 核心)

Hooks 解决类组件「复用逻辑复杂、this 混乱、组件拆分难」的问题,核心 Hooks 及场景:

Hook 名称 核心作用 适用场景
useState 声明组件状态 管理组件内部简单状态(如计数、输入值)
useEffect 处理副作用 数据请求、DOM操作、定时器/清理
useContext 读取Context数据 跨组件传值(避免Props透传)
useRef 保存可变值/访问DOM 获取DOM元素、保存定时器ID
useReducer 复杂状态管理(替代useState) 状态逻辑复杂、多状态联动(如表单)
useCallback 缓存函数(避免子组件重复渲染) 传递给子组件的回调函数
useMemo 缓存计算结果(避免重复计算) 复杂计算(如列表过滤、排序)
useLayoutEffect 同步执行副作用(DOM更新后立即执行) 需同步修改DOM样式(避免闪烁)
useImperativeHandle 自定义暴露给父组件的Ref方法 父组件调用子组件方法(少用)
示例:useReducer(复杂状态管理)
jsx 复制代码
import { useReducer } from 'react';

// 1. 定义reducer函数(纯函数)
const reducer = (state, action) => {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    case 'RESET':
      return { ...state, count: 0 };
    default:
      return state;
  }
};

// 2. 使用useReducer
const Counter = () => {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <div>
      <p>计数:{state.count}</p>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>-1</button>
      <button onClick={() => dispatch({ type: 'RESET' })}>重置</button>
    </div>
  );
};

2. Context API:跨组件传值

解决「Props 透传」(多层组件传值)问题,核心步骤:创建 Context → 提供 Provider → 消费数据。

jsx 复制代码
import { createContext, useContext, useState } from 'react';

// 1. 创建Context(默认值可选)
const ThemeContext = createContext('light');

// 2. 提供Context(Provider)
const ThemeProvider = ({ children }) => {
  const [theme, setTheme] = useState('light');

  const toggleTheme = () => {
    setTheme(prev => prev === 'light' ? 'dark' : 'light');
  };

  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
};

// 3. 消费Context(useContext)
const ThemedButton = () => {
  const { theme, toggleTheme } = useContext(ThemeContext);
  return (
    <button
      onClick={toggleTheme}
      style={{
        backgroundColor: theme === 'light' ? 'white' : 'black',
        color: theme === 'light' ? 'black' : 'white'
      }}
    >
      当前主题:{theme},切换主题
    </button>
  );
};

// 4. 使用
const App = () => {
  return (
    <ThemeProvider>
      <ThemedButton />
    </ThemeProvider>
  );
};

3. Refs 与 Portals

(1)Refs 进阶:useRef vs createRef
  • useRef:函数组件专用,每次渲染返回同一个Ref对象;
  • createRef:类组件/函数组件均可,每次渲染创建新对象。
(2)Portals:渲染到DOM任意位置

解决「父组件 overflow:hidden/ z-index 限制」问题(如弹窗、模态框):

jsx 复制代码
import { createPortal } from 'react-dom';

const Modal = ({ children }) => {
  // 找到public/index.html中的#modal-root
  const modalRoot = document.getElementById('modal-root');
  return createPortal(
    <div style={{ position: 'fixed', top: 0, left: 0, zIndex: 9999 }}>
      {children}
    </div>,
    modalRoot
  );
};

// 使用
const App = () => {
  return (
    <div style={{ overflow: 'hidden', height: '200px' }}>
      <Modal>
        <h2>这是一个弹窗</h2>
      </Modal>
    </div>
  );
};

4. Error Boundaries:错误捕获

防止子组件错误导致整个应用崩溃,仅能捕获类组件(函数组件需封装):

jsx 复制代码
import React, { Component } from 'react';

class ErrorBoundary extends Component {
  state = { hasError: false, error: null };

  // 捕获错误
  static getDerivedStateFromError(error) {
    return { hasError: true };
  }

  // 记录错误日志
  componentDidCatch(error, info) {
    console.error('组件错误:', error, info);
    this.setState({ error });
  }

  render() {
    if (this.state.hasError) {
      // 自定义错误UI
      return <div>出错了:{this.state.error?.message}</div>;
    }
    return this.props.children;
  }
}

// 使用
const BuggyComponent = () => {
  // 故意抛出错误
  throw new Error('组件内部错误!');
  return <p>正常内容</p>;
};

const App = () => {
  return (
    <ErrorBoundary>
      <BuggyComponent />
    </ErrorBoundary>
  );
};

5. 性能优化核心

(1)React.memo:缓存函数组件

浅比较Props,避免无意义重渲染:

jsx 复制代码
// 包裹组件,仅Props变化时重渲染
const MemoizedComponent = React.memo(({ name }) => {
  console.log('组件渲染了');
  return <p>{name}</p>;
});
(2)useCallback/useMemo:缓存函数/计算结果
jsx 复制代码
import { useCallback, useMemo, useState } from 'react';

const OptimizedComponent = () => {
  const [count, setCount] = useState(0);
  const [name, setName] = useState('张三');

  // 缓存函数:仅依赖name变化时重新创建
  const handleClick = useCallback(() => {
    console.log('姓名:', name);
  }, [name]);

  // 缓存计算结果:仅count变化时重新计算
  const doubleCount = useMemo(() => {
    console.log('计算doubleCount');
    return count * 2;
  }, [count]);

  return (
    <div>
      <p>计数:{count},双倍:{doubleCount}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <button onClick={handleClick}>打印姓名</button>
    </div>
  );
};
(3)懒加载:React.lazy + Suspense

减少首屏加载体积:

jsx 复制代码
import { lazy, Suspense } from 'react';

// 懒加载组件
const LazyComponent = lazy(() => import('./LazyComponent'));

const App = () => {
  return (
    <div>
      {/* Suspense:加载中占位 */}
      <Suspense fallback={<div>加载中...</div>}>
        <LazyComponent />
      </Suspense>
    </div>
  );
};

三、React 生态与工程化

1. React Router(路由管理,v6 主流)

核心功能:路由跳转、参数传递、嵌套路由、路由守卫。

jsx 复制代码
import {
  BrowserRouter as Router,
  Routes,
  Route,
  Link,
  useParams,
  useNavigate
} from 'react-router-dom';

// 页面组件
const Home = () => <h2>首页</h2>;
const User = () => {
  // 获取路由参数
  const { id } = useParams();
  // 编程式导航
  const navigate = useNavigate();
  return (
    <div>
      <h2>用户页:{id}</h2>
      <button onClick={() => navigate('/')}>返回首页</button>
    </div>
  );
};

// 嵌套路由
const Dashboard = () => {
  return (
    <div>
      <h2>控制台</h2>
      <Link to="profile">个人信息</Link>
      <Routes>
        <Route path="profile" element={<p>个人信息内容</p>} />
      </Routes>
    </div>
  );
};

// 路由配置
const App = () => {
  return (
    <Router>
      <nav>
        <Link to="/">首页</Link>
        <Link to="/user/123">用户123</Link>
        <Link to="/dashboard">控制台</Link>
      </nav>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/user/:id" element={<User />} />
        <Route path="/dashboard/*" element={<Dashboard />} />
      </Routes>
    </Router>
  );
};

2. 状态管理生态

  • 轻量场景:Context + useReducer(替代Redux);
  • 中大型项目:Redux Toolkit(RTK,简化Redux);
  • 服务端状态:React Query/SWR(处理异步数据,缓存、刷新、重试)。
Redux Toolkit 示例
jsx 复制代码
// store/slice/counterSlice.js
import { createSlice } from '@reduxjs/toolkit';

const counterSlice = createSlice({
  name: 'counter',
  initialState: { count: 0 },
  reducers: {
    increment: (state) => {
      state.count += 1; // RTK允许直接修改(内部用Immer)
    },
    decrement: (state) => {
      state.count -= 1;
    }
  }
});

export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;

// store/index.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './slice/counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer
  }
});

// 组件中使用
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement } from './store/slice/counterSlice';

const Counter = () => {
  const count = useSelector(state => state.counter.count);
  const dispatch = useDispatch();

  return (
    <div>
      <p>计数:{count}</p>
      <button onClick={() => dispatch(increment())}>+1</button>
      <button onClick={() => dispatch(decrement())}>-1</button>
    </div>
  );
};

// 根组件包裹Provider
import { Provider } from 'react-redux';
import { store } from './store';

const App = () => {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
};

3. 工程化配套

  • 打包构建:Vite/Webpack(处理ES6+、CSS、静态资源);
  • 代码规范:ESLint(语法检查)+ Prettier(代码格式化);
  • 测试:Jest(单元测试)+ React Testing Library(组件测试);
  • SSR/SSG:Next.js(React 服务端渲染框架,解决SEO、首屏加载);
  • 移动端:React Native(用React写原生App)。

四、React 最佳实践

  1. 组件设计:原子化拆分(基础组件→业务组件→页面组件),组合优于继承;
  2. 状态管理:局部状态用useState,跨组件用Context+useReducer,大型项目用RTK;
  3. 性能优化:避免不必要的渲染(React.memo/useCallback/useMemo),懒加载组件;
  4. 代码规范:组件命名PascalCase,文件按功能划分(如/components、/hooks、/store);
  5. 错误处理:用Error Boundary捕获错误,异步请求加loading/错误状态;
  6. Hooks 规则:仅在函数组件/自定义Hook中调用,仅在顶层调用(不能放if/for)。

总结

  1. 核心基础:React 以组件化为核心,JSX 是语法糖,Props 传值、State 管理内部状态,useEffect 处理副作用,覆盖了UI构建的基础能力;
  2. 进阶特性:Hooks 解决了类组件的痛点,Context 解决跨组件传值,Refs/Portals/Error Boundaries 完善特殊场景,性能优化(memo/useCallback/useMemo)提升应用体验;
  3. 生态工程化:React Router 管理路由,Redux Toolkit 处理状态,Vite/Next.js 提升工程化能力,遵循最佳实践可构建高可维护性的 React 应用。
相关推荐
天天向上10242 小时前
vue3 el-date-picker 需求是想既可以输入,也可以选择, 且开始时间不能大于结束时间, 当不符合条件时border变成红色
前端·javascript·vue.js
xiaotao1312 小时前
11. v4 版本升级指南
前端·css·tailwind
会飞的大可2 小时前
Web项目自动化测试方案
前端
盐水冰2 小时前
【WEB模型】CS架构&BS架构&HTML&CSS&JS
开发语言·前端·javascript
阿凤212 小时前
js文件怎么引入到vue3的项目中
开发语言·前端·javascript·vue.js
希望永不加班2 小时前
SpringBoot Web 模块核心组件:从 DispatcherServlet 讲起
java·前端·spring boot·后端·spring
asdzx672 小时前
使用 Python 将图片转换为 PDF (含合并)
前端·python·pdf
英俊潇洒美少年2 小时前
Vue 与 React 优缺点全面对比
前端·vue.js·react.js