写给 JavaScript 初学者的 React 完全指南

2 阅读10分钟

写给 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>
  )
}

组件化的好处

  1. 可复用Checkin 组件可以在其他页面使用
  2. 好维护:修改签到功能时,只需要改 Checkin 组件
  3. 分工明确:不同人可以负责不同组件

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 就像是一个"记忆盒子",里面装着 truefalse
  • setIsLoggedIn 就像是改变盒子内容的"遥控器"
  • 当盒子里的内容改变时,页面会自动更新

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>
}

会发生什么

  1. 页面第一次显示:Hello vue
  2. 3秒后,自动变成:Hello react
  3. 不需要手动刷新页面,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

  1. 帮助 React 识别哪些元素变化了
  2. 提高列表更新的性能
  3. 就像给列表项加上身份证号,每个都不一样

第五章:事件处理 - 让页面能交互

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 基础上的。我的学习建议:

  1. 先掌握这些 JavaScript 基础

    • 变量和常量(let, const)
    • 函数(function, 箭头函数)
    • 数组和对象
    • 数组的 map 方法
  2. 然后学习 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周)

  1. 学会写 JSX(在 JS 中写 HTML)
  2. 理解什么是组件
  3. 掌握 useState 的基本使用

第二阶段:实践(2-3周)

  1. 做一个待办事项应用(就像我代码中的 todos)
  2. 做一个简单的登录/注册界面
  3. 练习条件渲染和列表渲染

第三阶段:进阶(持续学习)

  1. 学习更多 React Hooks
  2. 学习组件间通信
  3. 学习路由、状态管理等

最后的鼓励

我刚开始学习 React 时,也觉得这些概念很抽象。但通过实际写代码,特别是像我的 App.jsxApp2.jsx 这样的练习,我逐渐理解了:

  1. React 并不神秘:它只是提供了一种更高效的方式来构建网页
  2. 组件化思想很重要:把大问题拆成小问题,每个组件解决一个小问题
  3. 状态管理是核心:理解 useState,就理解了 React 的一半

记住我代码中的这个例子,它包含了 React 最核心的概念:

// 状态
const [isLoggedIn, setIsLoggedIn] = useState(false)

// 事件处理
const toggleLogin = () => {
  setIsLoggedIn(!isLoggedIn)
}

// 条件渲染
{isLoggedIn ? <div>已登录</div> : <div>未登录</div>}

// 事件绑定
<button onClick={toggleLogin}>切换登录状态</button>

一个函数 + 一些状态 + JSX = 一个 React 组件

从现在开始,动手写代码吧!遇到问题就回头看我的代码示例,或者自己尝试修改我的代码看看效果。学习编程最有效的方法就是:多写,多练,多思考

加油,你一定能学会 React!