React 快速入门到精通教程从零基础到能写项目React 官方把它定义为用 JavaScript 构建用户界面的库核心思想是把页面拆成一个个组件再用数据驱动页面变化。React 官方快速入门也强调日常开发中最常用的能力包括组件、JSX、条件渲染、列表渲染、事件、状态和组件间数据共享。(React)文章目录React 快速入门到精通教程从零基础到能写项目一、React 是什么1. 专业解释2. 大白话理解3. 生活案例类比4. React 适合解决什么问题二、React 核心基础1. JSX概念解释大白话代码示例逐行解释常见错误面试追问2. 组件概念解释大白话代码示例逐行解释常见错误面试追问3. Props概念解释大白话代码示例逐行解释常见错误面试追问4. State概念解释大白话代码示例逐行解释常见错误面试追问5. 事件处理代码示例解释常见错误面试追问6. 条件渲染常见场景常见错误7. 列表渲染重点常见错误面试追问8. 表单处理大白话面试追问三、Hooks 重点讲解1. useState场景常见错误面试追问2. useEffect概念解释逐行解释常见错误面试追问3. useRef场景常见错误面试追问4. useMemo大白话场景常见错误5. useCallback大白话面试追问6. 自定义 Hook场景面试追问四、实战项目 1TodoList完整代码核心讲解面试追问五、实战项目 2搜索过滤列表业务场景常见错误六、实战项目 3可复用 Modal 组件组件设计重点面试追问七、组件封装教学1. 如何拆分组件2. 通用 Button 组件使用3. 通用 Card 组件使用八、进阶内容1. 组件通信2. 状态提升大白话3. Context场景4. React 性能优化5. React Router6. 常见项目目录结构九、React 高频面试题1. React 为什么需要虚拟 DOM2. key 的作用是什么3. useEffect 执行时机4. useMemo 和 useCallback 区别5. 受控组件和非受控组件6. React 组件通信方式7. React 性能优化方案十、React 学习路线图最后总结一、React 是什么1. 专业解释React 是一个用于构建用户界面的 JavaScript 库。它通过组件化、声明式渲染、状态驱动 UI的方式让开发者可以更高效地构建复杂前端应用。2. 大白话理解React 就像“搭积木”。一个页面不是一次性写成一大坨 HTML而是拆成页面 Header Sidebar Content Footer每一块都是组件组件可以复用、组合、传数据。3. 生活案例类比做一套乐高房子门 一个组件 窗户 一个组件 屋顶 一个组件 房间 多个组件组合 整栋房子 整个 React 应用以后你想换窗户不需要推倒整栋房子只改窗户组件。4. React 适合解决什么问题React 适合中后台管理系统电商网站社交应用数据可视化平台单页应用 SPA组件复用很多的业务系统React 官方“Thinking in React”也推荐先把 UI 拆成组件层级再确定每个组件的状态与数据流。(React)二、React 核心基础1. JSX概念解释JSX 是 JavaScript 的语法扩展看起来像 HTML但本质上会被编译成 JavaScript。大白话JSX 就是“在 JS 里写页面结构”。代码示例function App() { const name 小明; return ( div h1Hello, {name}/h1 p欢迎学习 React/p /div ); } export default App;逐行解释function App() {定义一个 React 函数组件。const name 小明;定义普通 JavaScript 变量。return (组件返回 JSX。h1Hello, {name}/h1用{}在 JSX 中插入 JS 表达式。export default App;导出组件。常见错误return ( h1标题/h1 p内容/p );错误JSX 必须有一个根节点。正确return ( h1标题/h1 p内容/p / );面试追问问JSX 是 HTML 吗答不是。JSX 是 JavaScript 的语法扩展最终会被编译成 React 元素。2. 组件概念解释组件是 React 应用的基本单位。React 应用就是由组件组成的树。大白话组件就是“页面零件”。代码示例function UserCard() { return ( div h2张三/h2 p前端工程师/p /div ); } function App() { return ( div UserCard / UserCard / /div ); } export default App;逐行解释function UserCard() {定义用户卡片组件。UserCard /在 App 组件中使用 UserCard。常见错误组件名小写function userCard() {}React 会把小写标签当成原生 HTML 标签。正确function UserCard() {}面试追问问React 为什么推荐组件化答为了复用、拆分复杂度、降低维护成本。3. Props概念解释Props 是父组件传给子组件的数据。大白话Props 就像“外卖订单备注”父组件告诉子组件该显示什么。代码示例function UserCard(props) { return ( div h2{props.name}/h2 p{props.job}/p /div ); } function App() { return ( div UserCard name张三 job前端工程师 / UserCard name李四 job后端工程师 / /div ); } export default App;逐行解释function UserCard(props)子组件接收 props。props.name读取父组件传入的 name。UserCard name张三 job前端工程师 /父组件传值。常见错误直接修改 propsprops.name 王五;错误。Props 是只读的。面试追问问Props 和 State 有什么区别答Props 是外部传入的State 是组件自己管理的。4. State概念解释State 是组件内部状态。状态变化后React 会重新渲染页面。React 官方文档说明State 可以让组件“记住”用户输入、选择等信息。(react.nodejs.cn)大白话State 就是组件自己的“小记事本”。代码示例import { useState } from react; function Counter() { const [count, setCount] useState(0); return ( div p当前数量{count}/p button onClick{() setCount(count 1)}加 1/button /div ); } export default Counter;逐行解释import { useState } from react;引入 useState。const [count, setCount] useState(0);定义状态 count初始值是 0。setCount(count 1)更新状态。常见错误直接改 statecount;错误。页面不会可靠更新。正确setCount(count 1);面试追问问setState 是同步还是异步答React 会批量处理状态更新不应该依赖修改后的 state 立即同步可读。需要基于旧值更新时用函数写法setCount(prev prev 1);5. 事件处理代码示例function App() { function handleClick() { alert(按钮被点击了); } return button onClick{handleClick}点击我/button; } export default App;解释onClick{handleClick}React 中事件名使用驼峰命名。常见错误button onClick{handleClick()}点击/button这样会在页面渲染时立即执行。正确button onClick{handleClick}点击/button面试追问问React 事件和原生 DOM 事件有什么区别答React 使用合成事件提供跨浏览器一致的事件行为。6. 条件渲染function App() { const isLogin true; return ( div {isLogin ? h1欢迎回来/h1 : h1请先登录/h1} /div ); } export default App;常见场景登录 / 未登录有数据 / 无数据加载中 / 加载完成常见错误if (isLogin) { return h1欢迎/h1; }这可以用但不能直接在 JSX 里面写 if 语句。7. 列表渲染function App() { const users [ { id: 1, name: 张三 }, { id: 2, name: 李四 }, ]; return ( ul {users.map(user ( li key{user.id}{user.name}/li ))} /ul ); } export default App;重点key必须稳定、唯一。常见错误li key{index}{user.name}/li如果列表会增删改尽量不要用 index。面试追问问key 的作用是什么答帮助 React 判断哪些元素新增、删除、移动从而提高更新效率并避免状态错乱。8. 表单处理import { useState } from react; function LoginForm() { const [username, setUsername] useState(); function handleSubmit(e) { e.preventDefault(); alert(提交用户名${username}); } return ( form onSubmit{handleSubmit} input value{username} onChange{e setUsername(e.target.value)} placeholder请输入用户名 / button typesubmit提交/button /form ); } export default LoginForm;大白话输入框的值交给 React 管这叫受控组件。面试追问问受控组件和非受控组件区别答受控组件由 state 控制表单值非受控组件通过 DOM 或 ref 获取值。三、Hooks 重点讲解Hooks 是 React 函数组件中使用状态、副作用、引用、缓存等能力的方式。React 官方文档也强调Hooks 可以组合使用并可以封装成自定义 Hook。(react.nodejs.cn)1. useStateimport { useState } from react; function LikeButton() { const [liked, setLiked] useState(false); return ( button onClick{() setLiked(!liked)} {liked ? 已点赞 : 点赞} /button ); } export default LikeButton;场景弹窗开关表单输入Tab 切换计数器常见错误setCount(count 1); setCount(count 1);可能只加一次。正确setCount(prev prev 1); setCount(prev prev 1);面试追问问为什么 useState 返回数组答方便开发者自定义变量名。2. useEffect概念解释useEffect 用来处理副作用比如请求接口、设置定时器、监听事件。import { useEffect, useState } from react; function UserList() { const [users, setUsers] useState([]); useEffect(() { fetch(https://jsonplaceholder.typicode.com/users) .then(res res.json()) .then(data setUsers(data)); }, []); return ( ul {users.map(user ( li key{user.id}{user.name}/li ))} /ul ); } export default UserList;逐行解释useEffect(() {组件渲染后执行副作用。fetch(...)请求接口。}, []);空依赖数组表示组件首次挂载后执行一次。常见错误忘记依赖项useEffect(() { console.log(keyword); }, []);如果 effect 依赖 keyword应写useEffect(() { console.log(keyword); }, [keyword]);面试追问问useEffect 执行时机答无依赖每次渲染后执行 空数组首次挂载后执行一次 有依赖依赖变化后执行 return 函数组件卸载或下次 effect 执行前清理3. useRefimport { useRef } from react; function FocusInput() { const inputRef useRef(null); function handleFocus() { inputRef.current.focus(); } return ( div input ref{inputRef} placeholder请输入内容 / button onClick{handleFocus}聚焦输入框/button /div ); } export default FocusInput;场景获取 DOM保存不会触发渲染的数据定时器 ID常见错误以为 ref 改变会触发页面更新。不会。面试追问问useRef 和 useState 区别答useState 更新会触发渲染useRef 更新不会触发渲染。4. useMemoimport { useMemo, useState } from react; function ProductList() { const [keyword, setKeyword] useState(); const products [苹果, 香蕉, 橙子, 西瓜]; const filteredProducts useMemo(() { return products.filter(item item.includes(keyword)); }, [keyword]); return ( div input value{keyword} onChange{e setKeyword(e.target.value)} / ul {filteredProducts.map(item ( li key{item}{item}/li ))} /ul /div ); } export default ProductList;大白话useMemo 是“缓存计算结果”。场景大列表过滤复杂计算避免重复计算常见错误滥用 useMemo。简单计算不需要缓存。5. useCallbackimport { useCallback, useState } from react; function Child({ onClick }) { return button onClick{onClick}子组件按钮/button; } function App() { const [count, setCount] useState(0); const handleClick useCallback(() { console.log(点击子组件); }, []); return ( div p{count}/p button onClick{() setCount(count 1)}加 1/button Child onClick{handleClick} / /div ); } export default App;大白话useCallback 是“缓存函数”。面试追问问useMemo 和 useCallback 区别答useMemo 缓存计算结果 useCallback 缓存函数本身6. 自定义 Hookimport { useEffect, useState } from react; function useWindowWidth() { const [width, setWidth] useState(window.innerWidth); useEffect(() { function handleResize() { setWidth(window.innerWidth); } window.addEventListener(resize, handleResize); return () { window.removeEventListener(resize, handleResize); }; }, []); return width; } function App() { const width useWindowWidth(); return h1当前窗口宽度{width}/h1; } export default App;场景封装请求逻辑封装权限逻辑封装窗口监听封装表单逻辑面试追问问自定义 Hook 为什么必须以 use 开头答方便 React 识别 Hook 调用规则也方便 ESLint 检查。四、实战项目 1TodoList完整代码import { useState } from react; function TodoList() { const [text, setText] useState(); const [todos, setTodos] useState([]); function addTodo() { if (!text.trim()) return; const newTodo { id: Date.now(), title: text, done: false, }; setTodos([...todos, newTodo]); setText(); } function toggleTodo(id) { setTodos( todos.map(todo todo.id id ? { ...todo, done: !todo.done } : todo ) ); } function deleteTodo(id) { setTodos(todos.filter(todo todo.id ! id)); } return ( div h1TodoList/h1 input value{text} onChange{e setText(e.target.value)} placeholder请输入任务 / button onClick{addTodo}添加/button ul {todos.map(todo ( li key{todo.id} span onClick{() toggleTodo(todo.id)} style{{ textDecoration: todo.done ? line-through : none, cursor: pointer, }} {todo.title} /span button onClick{() deleteTodo(todo.id)}删除/button /li ))} /ul /div ); } export default TodoList;核心讲解const [text, setText] useState();保存输入框内容。const [todos, setTodos] useState([]);保存任务列表。setTodos([...todos, newTodo]);不能直接 push要创建新数组。todos.map(...)用于更新某一项。todos.filter(...)用于删除某一项。面试追问问为什么不能直接 todos.push答React 状态更新依赖引用变化。直接 push 会修改原数组可能导致 React 无法正确感知变化。五、实战项目 2搜索过滤列表import { useMemo, useState } from react; function SearchList() { const [keyword, setKeyword] useState(); const users [ { id: 1, name: 张三, role: 前端 }, { id: 2, name: 李四, role: 后端 }, { id: 3, name: 王五, role: 测试 }, ]; const filteredUsers useMemo(() { return users.filter(user user.name.includes(keyword) || user.role.includes(keyword) ); }, [keyword]); return ( div h1用户搜索/h1 input value{keyword} onChange{e setKeyword(e.target.value)} placeholder请输入姓名或岗位 / ul {filteredUsers.map(user ( li key{user.id} {user.name} - {user.role} /li ))} /ul /div ); } export default SearchList;业务场景后台用户管理商品搜索订单筛选城市列表过滤常见错误users.filter(...)如果数据量很大每次渲染都计算可能影响性能。可以用 useMemo 缓存。六、实战项目 3可复用 Modal 组件import { useState } from react; function Modal({ open, title, children, onClose }) { if (!open) return null; return ( div style{styles.mask} div style{styles.modal} h2{title}/h2 div{children}/div button onClick{onClose}关闭/button /div /div ); } const styles { mask: { position: fixed, inset: 0, background: rgba(0,0,0,0.4), display: flex, alignItems: center, justifyContent: center, }, modal: { width: 400, padding: 24, background: #fff, borderRadius: 8, }, }; function App() { const [open, setOpen] useState(false); return ( div button onClick{() setOpen(true)}打开弹窗/button Modal open{open} title提示 onClose{() setOpen(false)} p这是一个可复用 Modal 组件。/p /Modal /div ); } export default App;组件设计重点open控制弹窗显示隐藏。title弹窗标题。children弹窗内容插槽。onClose关闭回调。面试追问问children 是什么答children 是 React 中特殊的 prop用于接收组件标签内部的内容。七、组件封装教学1. 如何拆分组件拆分原则一个组件只做一件事 重复出现的 UI 抽成组件 复杂页面按业务模块拆分React 官方也建议构建 UI 时先把界面拆成组件层级再连接数据流。(React)2. 通用 Button 组件function Button({ type primary, children, onClick, disabled false }) { const style { padding: 8px 16px, border: none, borderRadius: 4, cursor: disabled ? not-allowed : pointer, background: type primary ? #1677ff : #ddd, color: type primary ? #fff : #333, }; return ( button style{style} onClick{onClick} disabled{disabled} {children} /button ); } export default Button;使用Button typeprimary onClick{() alert(提交)} 提交 /Button3. 通用 Card 组件function Card({ title, children }) { return ( div style{{ border: 1px solid #eee, borderRadius: 8, padding: 16, marginBottom: 16, }} h3{title}/h3 div{children}/div /div ); } export default Card;使用Card title用户信息 p姓名张三/p p岗位前端工程师/p /Card八、进阶内容1. 组件通信常见方式父传子props 子传父回调函数 兄弟通信状态提升 跨层级通信Context 复杂状态状态管理库2. 状态提升import { useState } from react; function InputBox({ value, onChange }) { return ( input value{value} onChange{e onChange(e.target.value)} / ); } function Preview({ value }) { return p预览{value}/p; } function App() { const [text, setText] useState(); return ( div InputBox value{text} onChange{setText} / Preview value{text} / /div ); } export default App;大白话两个组件都需要同一份数据就把数据放到它们共同的父组件。3. Contextimport { createContext, useContext } from react; const ThemeContext createContext(light); function Toolbar() { const theme useContext(ThemeContext); return div当前主题{theme}/div; } function App() { return ( ThemeContext.Provider valuedark Toolbar / /ThemeContext.Provider ); } export default App;场景主题登录用户信息多语言权限信息4. React 性能优化常见方案React.memo缓存组件 useMemo缓存计算结果 useCallback缓存函数 合理使用 key 列表虚拟滚动 避免不必要的状态提升 组件拆分 按需加载5. React RouterReact Router 是 React 生态中常用的路由库。官方文档介绍 React Router v7 是非破坏性升级并支持逐步衔接 React 19 相关能力。(reactrouter.com)import { createBrowserRouter, RouterProvider, Link, } from react-router-dom; function Home() { return h1首页/h1; } function About() { return h1关于我们/h1; } function Layout() { return ( div Link to/首页/Link Link to/about关于/Link /div ); } const router createBrowserRouter([ { path: /, element: Home / }, { path: /about, element: About / }, ]); function App() { return RouterProvider router{router} /; } export default App;6. 常见项目目录结构src ├── assets 静态资源 ├── components 通用组件 ├── pages 页面组件 ├── hooks 自定义 Hook ├── utils 工具函数 ├── services 接口请求 ├── router 路由配置 ├── store 状态管理 ├── App.jsx └── main.jsx九、React 高频面试题1. React 为什么需要虚拟 DOM虚拟 DOM 是 JS 对象形式的 UI 描述。React 通过比较前后虚拟 DOM尽量减少真实 DOM 操作。大白话真实 DOM 很贵虚拟 DOM 像“草稿纸”先在草稿纸上算清楚哪里变了再去改真实页面。2. key 的作用是什么key 帮助 React 识别列表中每一项的身份。错误list.map((item, index) li key{index}{item.name}/li)更推荐list.map(item li key{item.id}{item.name}/li)3. useEffect 执行时机useEffect(() { console.log(每次渲染后执行); }); useEffect(() { console.log(只在挂载后执行一次); }, []); useEffect(() { console.log(keyword 变化时执行); }, [keyword]);4. useMemo 和 useCallback 区别useMemo缓存值 useCallback缓存函数等价理解useCallback(fn, deps)约等于useMemo(() fn, deps)5. 受控组件和非受控组件受控组件input value{value} onChange{e setValue(e.target.value)} /非受控组件input ref{inputRef} /6. React 组件通信方式父传子props 子传父回调函数 兄弟通信状态提升 跨层级通信Context 复杂全局状态Redux / Zustand / Jotai 等7. React 性能优化方案1. 使用 React.memo 减少组件重复渲染 2. 使用 useMemo 缓存复杂计算 3. 使用 useCallback 缓存函数 4. 避免无意义的 state 5. 大列表使用虚拟滚动 6. 路由懒加载 7. 合理拆分组件 8. 使用稳定 key十、React 学习路线图第一阶段JavaScript 基础 变量、函数、数组、对象、ES6、模块化、异步 第二阶段React 基础 JSX、组件、Props、State、事件、列表、表单 第三阶段Hooks useState、useEffect、useRef、useMemo、useCallback、自定义 Hook 第四阶段项目实战 TodoList、搜索列表、Modal、后台管理系统 第五阶段工程化 Vite、ESLint、Prettier、Git、接口请求、环境变量 第六阶段进阶能力 Context、路由、权限、性能优化、组件封装 第七阶段面试准备 虚拟 DOM、key、Hooks 原理、组件通信、性能优化最后总结React 学习不要只背概念。正确路线是先学组件 再学状态 再学 Hooks 再做项目 最后补面试原理真正掌握 React 的标志不是“知道 useState 是什么”而是你能独立完成一个可维护的页面 一套可复用组件 一次清晰的数据流设计 一个能解释给面试官听的项目