写给 JavaScript 初学者的 React 完全指南
引言:从零开始,我们一起学 React
如果你是 JavaScript 初学者,觉得 React 很难懂,别担心!我曾经也是从零开始学习的。今天,我用最简单的方式,结合我自己写的代码,带你一步步理解 React 的核心概念。保证每个概念都有代码示例,而且都是我自己学习时写的真实代码!
第一章:什么是 JSX?比 HTML 还简单的语法
1.1 JSX 就像在 JavaScript 里写 HTML
想象一下,你可以在 JavaScript 文件中直接写 HTML,这就是 JSX!
// 看看我写的代码,是不是很像 HTML?
const element = <h2>JSX 是React 中用于描述用户界面的语法扩展</h2>
简单理解:JSX 就是在 JavaScript 里面写 HTML 标签。
1.2 为什么要用 JSX?一个对比你就懂了
传统方式(很复杂):
// 不用 JSX,创建元素需要这样:
const element = document.createElement('h2')
element.textContent = 'Hello World'
document.body.appendChild(element)
使用 JSX(很简单):
// 使用 JSX,直接写:
const element = <h2>Hello World</h2>
看到区别了吗?JSX 让创建页面元素变得跟写 HTML 一样简单!
1.3 JSX 的几个重要规则
规则1:最外层只能有一个标签
// ❌ 错误写法(多个并列标签)
function Wrong() {
return (
<h1>标题</h1>
<p>内容</p>
)
}
// ✅ 正确写法(用一个标签包裹起来)
function Right() {
return (
<div> {/* 这个 div 就像一个大盒子 */}
<h1>标题</h1>
<p>内容</p>
</div>
)
}
规则2:用 className 代替 class
// ❌ 错误写法
<div class="title">Hello</div>
// ✅ 正确写法
<div className="title">Hello</div>
为什么:因为 class 在 JavaScript 中是定义类的关键字,为了避免冲突,React 用 className。
规则3:JavaScript 表达式要放在 {} 里
const name = '小明'
// 在 JSX 中使用 JavaScript 变量
const element = <h1>你好,{name}</h1>
// 渲染结果:<h1>你好,小明</h1>
第二章:React 组件 - 就像搭积木一样简单
2.1 什么是组件?就是一个函数
在 React 中,组件就是一个返回 JSX 的函数:
// 定义一个最简单的组件
function Welcome() {
return <h1>欢迎学习 React!</h1>
}
// 使用这个组件(就像使用 HTML 标签一样)
function App() {
return (
<div>
<Welcome />
</div>
)
}
2.2 为什么要用组件?看看我的掘金首页例子
我模仿掘金首页写了一个例子,用组件化的思想来构建:
// 我把一个完整的页面拆成了几个小部分:
// 1. 头部组件 - 专门负责显示网站标题
function JuejinHeader() {
return (
<header>
<h1>掘金首页</h1>
</header>
)
}
// 2. 文章列表组件 - 专门负责显示文章
function Articles() {
return (
<div>
<h2>文章列表</h2>
<p>React 入门教程</p>
<p>JavaScript 基础</p>
</div>
)
}
// 3. 签到组件 - 专门负责签到功能
function Checkin() {
return (
<div>
<h2>每日签到</h2>
<button>点击签到</button>
</div>
)
}
// 4. 主组件 - 把所有小组件组合起来
function App() {
return (
<div>
{/* 使用头部组件 */}
<JuejinHeader />
<main>
{/* 使用文章列表组件 */}
<Articles />
<aside>
{/* 使用签到组件 */}
<Checkin />
</aside>
</main>
</div>
)
}
组件化的好处:
- 可复用:
Checkin组件可以在其他页面使用 - 好维护:修改签到功能时,只需要改
Checkin组件 - 分工明确:不同人可以负责不同组件
2.3 组件命名的约定
在 React 中,组件名必须以大写字母开头:
// ✅ 正确:大写字母开头
function MyComponent() {
return <div>Hello</div>
}
// ❌ 错误:小写字母开头(会被认为是 HTML 标签)
function mycomponent() {
return <div>Hello</div>
}
第三章:useState - React 的"记忆"功能
3.1 为什么需要状态?
想象一下,你的网页需要记住一些信息,比如:
- 用户是否登录
- 计数器当前的值
- 待办事项列表
在 React 中,这些"记忆"就是通过 状态(state) 实现的。
3.2 useState 基本用法
让我们一步步理解,看我写的登录状态例子:
// 第一步:导入 useState
import { useState } from 'react'
function App() {
// 第二步:使用 useState
// 它返回一个数组,包含两个东西:
// 1. 当前状态值(isLoggedIn)
// 2. 修改状态的函数(setIsLoggedIn)
const [isLoggedIn, setIsLoggedIn] = useState(false)
// ↑ 初始值设为 false,表示未登录
// 第三步:使用状态
return (
<div>
{/* 根据登录状态显示不同文字 */}
{isLoggedIn ? <div>已登录</div> : <div>未登录</div>}
{/* 点击按钮改变状态 */}
<button onClick={() => setIsLoggedIn(!isLoggedIn)}>
{isLoggedIn ? '退出登录' : '登录'}
</button>
</div>
)
}
形象理解:
isLoggedIn就像是一个"记忆盒子",里面装着true或falsesetIsLoggedIn就像是改变盒子内容的"遥控器"- 当盒子里的内容改变时,页面会自动更新
3.3 多个状态的管理
在我的代码中,我管理了多个状态:
function App() {
// 1. 字符串状态 - 名字
const [name, setName] = useState('vue')
// name 初始值是 'vue'
// 2. 数组状态 - 待办事项列表
const [todos, setTodos] = useState([
{ id: 1, title: '学习react', done: false },
{ id: 2, title: '学习vue', done: false }
])
// 3. 布尔状态 - 是否登录
const [isLoggedIn, setIsLoggedIn] = useState(false)
// 每个状态都有自己的"记忆盒子"和"遥控器"
// 它们之间互不干扰
}
3.4 自动更新的魔法
看看我这个有趣的例子:
function App() {
const [name, setName] = useState('vue')
// 3秒后自动改变名字
setTimeout(() => {
setName('react') // 从 'vue' 变成 'react'
}, 3000)
return <h1>Hello {name}</h1>
}
会发生什么:
- 页面第一次显示:Hello vue
- 3秒后,自动变成:Hello react
- 不需要手动刷新页面,React 会自动更新!
这就是 React 最神奇的地方:状态改变,UI 自动更新。
第四章:条件渲染和列表渲染
4.1 条件渲染 - 像 if-else 一样简单
在我的待办事项代码中,我用了条件渲染:
function TodoList() {
const [todos, setTodos] = useState([
{ id: 1, title: '学习react' },
{ id: 2, title: '学习vue' }
])
return (
<div>
{/* 条件渲染:如果 todos 有内容就显示列表,否则显示提示 */}
{
todos.length > 0 ? (
// 条件成立时显示的内容
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
) : (
// 条件不成立时显示的内容
<div>暂无待办事项</div>
)
}
</div>
)
}
简单理解:
todos.length > 0 ? A : B就像 if-else 语句- 如果 todo 数量 > 0,显示列表(A)
- 否则,显示"暂无待办事项"(B)
4.2 列表渲染 - 用 map 显示数组内容
列表渲染非常常用,看我的例子:
const todos = [
{ id: 1, title: '学习react' },
{ id: 2, title: '学习vue' },
{ id: 3, title: '学习JavaScript' }
]
function TodoList() {
return (
<ul>
{
// 用 map 把数组变成 JSX 元素
todos.map(item => (
<li key={item.id}>{item.title}</li>
))
}
</ul>
)
}
// 渲染结果:
// <ul>
// <li>学习react</li>
// <li>学习vue</li>
// <li>学习JavaScript</li>
// </ul>
重要提示:列表中的每个元素都需要 key 属性
// ✅ 正确:有 key
<li key={item.id}>{item.title}</li>
// ❌ 错误:没有 key(React 会警告)
<li>{item.title}</li>
为什么需要 key:
- 帮助 React 识别哪些元素变化了
- 提高列表更新的性能
- 就像给列表项加上身份证号,每个都不一样
第五章:事件处理 - 让页面能交互
5.1 处理点击事件
在我写的登录例子中,我处理了按钮点击:
function LoginButton() {
const [isLoggedIn, setIsLoggedIn] = useState(false)
// 点击按钮时调用的函数
const handleClick = () => {
// 把登录状态取反
// 如果原来是 true,变成 false;如果原来是 false,变成 true
setIsLoggedIn(!isLoggedIn)
}
return (
<div>
<p>{isLoggedIn ? '已登录' : '未登录'}</p>
{/* 注意:onClick 的 C 是大写 */}
<button onClick={handleClick}>
{isLoggedIn ? '退出登录' : '登录'}
</button>
</div>
)
}
5.2 事件处理的不同写法
// 写法1:先定义函数,再使用
function handleClick() {
console.log('按钮被点击了')
}
<button onClick={handleClick}>按钮</button>
// 写法2:使用箭头函数
<button onClick={() => {
console.log('按钮被点击了')
}}>按钮</button>
// 写法3:箭头函数调用已定义的函数
<button onClick={() => handleClick()}>按钮</button>
第六章:完整代码解析 - 一步步理解
6.1 我的 App.jsx 完整解析
// 第1步:导入需要的功能
import { useState, createElement } from 'react'
import './App.css'
// 第2步:定义 App 组件
function App() {
// 第3步:定义状态(组件的"记忆")
const [name, setName] = useState('vue') // 名字状态
const [todos, setTodos] = useState([ // 待办事项状态
{ id: 1, title: '学习react', done: false },
{ id: 2, title: '学习vue', done: false }
])
const [isLoggedIn, setIsLoggedIn] = useState(false) // 登录状态
// 第4步:定义事件处理函数
const toggleLogin = () => {
// 切换登录状态(true ↔ false)
setIsLoggedIn(!isLoggedIn)
}
// 第5步:定义 JSX 元素
const element = <h2>JSX 是React 中用于描述用户界面的语法扩展</h2>
const element2 = createElement('h2', null, 'JSX 是React 中用于描述用户界面的语法扩展')
// 第6步:演示状态自动更新(3秒后改变名字)
setTimeout(() => {
setName('react') // 从 'vue' 变成 'react'
}, 3000)
// 第7步:返回 JSX(页面的内容)
return(
<>
{/* 显示 JSX 元素 */}
{element}
{element2}
{/* 显示动态内容 */}
<h1>Hello <span className="title">{name}</span></h1>
{/* 条件渲染:根据 todos 长度显示不同内容 */}
{
todos.length > 0 ? (
<ul>
{
todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))
}
</ul>
) : (<div>暂无待办事项</div>)
}
{/* 条件渲染:根据登录状态显示不同内容 */}
{isLoggedIn ? <div>已登录</div> : <div>未登录</div>}
{/* 事件处理:点击按钮切换登录状态 */}
<button onClick={toggleLogin}>
{isLoggedIn ? '退出登录' : '登录'}
</button>
</>
)
}
// 第8步:导出组件,让其他文件可以使用
export default App
6.2 我的 App2.jsx 完整解析
// 这个文件展示了如何把大页面拆分成小组件
// 组件1:掘金网站的头部
function JuejinHeader() {
return (
<div>
<header>
<h1>掘金首页</h1>
</header>
</div>
)
}
// 组件2:文章列表
const Articles = () => {
return (
<div>
<h2>文章列表</h2>
</div>
)
}
// 组件3:签到功能
const Checkin = () => {
return (
<div>
<h2>签到</h2>
</div>
)
}
// 组件4:热门文章
const TopArticles = () => {
return (
<div>
<h2>热门文章</h2>
</div>
)
}
// 主组件:把所有小组件组合起来
function App() {
return (
<div>
{/* 使用头部组件 */}
<JuejinHeader />
{/* 主要内容区域 */}
<main>
{/* 使用文章列表组件 */}
<Articles />
{/* 侧边栏 */}
<aside>
{/* 使用签到组件 */}
<Checkin />
{/* 使用热门文章组件 */}
<TopArticles />
</aside>
</main>
</div>
)
}
// 导出主组件
export default App
第七章:常见问题解答
7.1 我是 JavaScript 新手,能学会 React 吗?
当然可以! React 虽然有一些新概念,但都是建立在 JavaScript 基础上的。我的学习建议:
-
先掌握这些 JavaScript 基础:
- 变量和常量(let, const)
- 函数(function, 箭头函数)
- 数组和对象
- 数组的 map 方法
-
然后学习 React:
- JSX(就是 HTML 写在 JS 里)
- 组件(就是返回 JSX 的函数)
- useState(就是让组件有"记忆")
7.2 为什么我的代码报错了?
根据我的经验,新手常犯的错误:
// 错误1:最外层多个标签
function Wrong() {
return (
<h1>标题1</h1> // ❌ 这里会报错
<h2>标题2</h2>
)
}
// 正确:用一个标签包裹
function Right() {
return (
<div> {/* ✅ 用一个 div 包裹所有内容 */}
<h1>标题1</h1>
<h2>标题2</h2>
</div>
)
}
7.3 如何开始我的第一个 React 项目?
最简单的方式是使用官方工具:
# 在命令行中输入(确保已安装 Node.js)
npx create-react-app my-first-app
# 进入项目文件夹
cd my-first-app
# 启动项目
npm start
然后打开 src/App.js,就可以开始写代码了!
学习路线建议
根据我自己的学习经历,建议按这个顺序学习:
第一阶段:基础(1-2周)
- 学会写 JSX(在 JS 中写 HTML)
- 理解什么是组件
- 掌握 useState 的基本使用
第二阶段:实践(2-3周)
- 做一个待办事项应用(就像我代码中的 todos)
- 做一个简单的登录/注册界面
- 练习条件渲染和列表渲染
第三阶段:进阶(持续学习)
- 学习更多 React Hooks
- 学习组件间通信
- 学习路由、状态管理等
最后的鼓励
我刚开始学习 React 时,也觉得这些概念很抽象。但通过实际写代码,特别是像我的 App.jsx 和 App2.jsx 这样的练习,我逐渐理解了:
- React 并不神秘:它只是提供了一种更高效的方式来构建网页
- 组件化思想很重要:把大问题拆成小问题,每个组件解决一个小问题
- 状态管理是核心:理解 useState,就理解了 React 的一半
记住我代码中的这个例子,它包含了 React 最核心的概念:
// 状态
const [isLoggedIn, setIsLoggedIn] = useState(false)
// 事件处理
const toggleLogin = () => {
setIsLoggedIn(!isLoggedIn)
}
// 条件渲染
{isLoggedIn ? <div>已登录</div> : <div>未登录</div>}
// 事件绑定
<button onClick={toggleLogin}>切换登录状态</button>
一个函数 + 一些状态 + JSX = 一个 React 组件
从现在开始,动手写代码吧!遇到问题就回头看我的代码示例,或者自己尝试修改我的代码看看效果。学习编程最有效的方法就是:多写,多练,多思考。
加油,你一定能学会 React!