Skip to content

React 快速入门 ⭐ ​

了解 React 并搭建开发环境


学习目标 ​

  • 理解 React 是什么及核心特点
  • 搭建 React 开发环境
  • 掌握 JSX 语法、条件渲染、列表渲染和事件处理
  • 创建第一个 React 组件

生活化比喻 ​

React 就像"乐高积木":

比喻对应:

┌──────────────────────────────────────────────────────┐
│                  乐高积木                             │
├──────────────────────────────────────────────────────┤
│                                                      │
│    组件 = 乐高积木块                                  │
│    ─────────────                                     │
│    每个积木块独立,可以拼装                          │
│    一块是窗户,一块是门,拼起来就是房子              │
│                                                      │
│    JSX = 拼装说明书                                 │
│    ─────────────                                     │
│    用类似 HTML 的语法描述怎么拼装                    │
│    最终会被翻译成真正的拼装步骤                      │
│                                                      │
│    Props = 积木块的颜色/形状参数                     │
│    ─────────────                                     │
│    同样的积木块,不同参数可以拼出不同效果            │
│    Props 从父组件传进来,不能自己改                  │
│                                                      │
│    State = 积木块当前状态                            │
│    ─────────────                                     │
│    积木块自己内部的配置,可以改变                    │
│    改变了就会重新拼装                                │
│                                                      │
│    声明式 = 描述最终效果                             │
│    ─────────────                                     │
│    不说"先拿这块再放那块"                            │
│    只说"我要一个红色窗户"                            │
│                                                      │
└──────────────────────────────────────────────────────┘

L1 理解层:会用 ​

React 基础 ​

最简示例(1-3行):

jsx
function App() {
    return <h1>Hello React!</h1>
}

详细示例 — 单文件组件:

jsx
// src/App.jsx
import { useState } from 'react'

function App() {
    const [message, setMessage] = useState('Hello React!')

    return (
        <div className="app">
            <h1>{message}</h1>
            <button onClick={() => setMessage('Clicked!')}>
                点击我
            </button>
        </div>
    )
}

export default App

JSX 语法 ​

语法结构图:

JSX 规则:

{{ 表达式 }}           → 插入 JavaScript 表达式
className="..."        → class 属性(不是 class)
onClick={fn}           → 事件绑定(驼峰命名)
<tag />                → 自闭合标签
<>...</>               → Fragment(不需要额外 div)
{condition && <X />}   → 条件渲染
{items.map(item => ...)} → 列表渲染

最简示例(1-3行):

jsx
const name = '张三'
const el = <h1>Hello, {name}</h1>

详细示例:

jsx
function App() {
    const title = '标题'
    const imageUrl = 'photo.jpg'
    const isActive = true
    const items = [{ id: 1, name: '苹果' }, { id: 2, name: '香蕉' }]

    return (
        <div>
            {/* 变量插值 */}
            <h1>{title}</h1>
            <p>明年:{25 + 1} 岁</p>
            <p>状态:{isActive ? '开' : '关'}</p>

            {/* 属性绑定 */}
            <img src={imageUrl} alt="照片" />
            <div className={isActive ? 'active' : ''}>内容</div>
            <button disabled={!isActive}>按钮</button>

            {/* 内联样式 */}
            <div style={{ color: 'red', fontSize: '16px' }}>红色</div>

            {/* Fragment — 不需要额外 div */}
            <>
                <h2>标题</h2>
                <p>内容</p>
            </>

            {/* 条件渲染 */}
            {items.length > 0 ? <p>有 {items.length} 项</p> : <p>空</p>}
            {isActive && <span>活跃</span>}

            {/* 列表渲染 */}
            <ul>
                {items.map(item => (
                    <li key={item.id}>{item.name}</li>
                ))}
            </ul>
        </div>
    )
}

事件处理 ​

最简示例(1-3行):

jsx
<button onClick={() => setCount(c => c + 1)}>+1</button>
<form onSubmit={(e) => { e.preventDefault(); handleSubmit() }}>

详细示例:

jsx
function App() {
    const [count, setCount] = useState(0)

    const handleClick = (msg) => {
        console.log(msg)
        setCount(prev => prev + 1)
    }

    return (
        <div>
            {/* 直接引用函数 */}
            <button onClick={handleClick}>点击</button>

            {/* 箭头函数传参 */}
            <button onClick={() => handleClick('参数')}>传参</button>

            {/* 阻止默认行为 */}
            <form onSubmit={(e) => {
                e.preventDefault()
                console.log('提交')
            }}>
                <button type="submit">提交</button>
            </form>
        </div>
    )
}

L2 实践层:用好 ​

反模式:不要这样做 ​

jsx
// ❌ 错误:组件名小写
function myComponent() { return <div>错</div> }

// ✅ 正确:首字母大写
function MyComponent() { return <div>对</div> }
jsx
// ❌ 错误:返回多个根元素
function Bad() {
    return (
        <h1>标题</h1>
        <p>内容</p>
    )
}

// ✅ 正确:用 Fragment 包裹
function Good() {
    return (
        <>
            <h1>标题</h1>
            <p>内容</p>
        </>
    )
}
jsx
// ❌ 错误:用 index 做 key
{items.map((item, i) => <li key={i}>{item.name}</li>)}

// ✅ 正确:用唯一 ID
{items.map(item => <li key={item.id}>{item.name}</li>)}

适用场景 ​

场景推荐方案示例
条件简单三元表达式{show ? <A /> : <B />}
只显示一种&& 短路{show && <A />}
列表渲染map + keyitems.map(item => <li key={item.id}>)
阻止默认行为e.preventDefault()表单提交

L3 专家层:深入 ​

JSX 编译原理 ​

JSX 编译流程:

JSX 代码:
  <div className="app">
    <h1>Hello</h1>
  </div>

编译为:
  React.createElement('div', { className: 'app' },
    React.createElement('h1', null, 'Hello')
  )

运行时返回虚拟 DOM 对象:
  { type: 'div', props: { className: 'app', children: [...] } }

知识关联 ​

React 快速入门关联:

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  环境搭建   │────→│  JSX 语法   │────→│  事件处理   │
│  Vite/      │     │  插值/      │     │  onClick/   │
│  入口文件   │     │  属性/      │     │  onSubmit   │
└─────────────┘     │  条件/      │     └─────────────┘
                    │  列表       │
                    └─────────────┘

术语定义 ​

术语定义示例
JSXJavaScript 语法扩展,允许在 JS 中写 HTML -like 代码<h1>Hello</h1>
组件返回 JSX 的函数,首字母必须大写function App() { }
Props从父组件传递给子组件的数据(只读)<Child name="张三" />
State组件内部的可变数据const [count, setCount] = useState(0)
Fragment不产生额外 DOM 元素的包裹器<>...</>
虚拟 DOM用 JS 对象描述的真实 DOM 结构React.createElement 返回的对象

实践练习 ​

练习:Todo 列表 ​

jsx
import { useState } from 'react'

function App() {
    const [todos, setTodos] = useState([])
    const [input, setInput] = useState('')

    const addTodo = (e) => {
        e.preventDefault()
        if (!input.trim()) return
        setTodos([...todos, { id: Date.now(), text: input }])
        setInput('')
    }

    const removeTodo = (id) => {
        setTodos(todos.filter(t => t.id !== id))
    }

    return (
        <div>
            <h1>Todo 列表</h1>
            <form onSubmit={addTodo}>
                <input value={input} onChange={e => setInput(e.target.value)} placeholder="输入任务..." />
                <button type="submit">添加</button>
            </form>
            <ul>
                {todos.map(todo => (
                    <li key={todo.id}>
                        {todo.text}
                        <button onClick={() => removeTodo(todo.id)}>删除</button>
                    </li>
                ))}
            </ul>
            {todos.length > 0 && <p>共 {todos.length} 项</p>}
        </div>
    )
}

export default App

常见问题 ​

Q1:组件名为什么必须大写? ​

React 通过首字母大小写区分 HTML 元素和自定义组件:

jsx
<div />     → HTML div 元素
<Div />     → 自定义 Div 组件

Q2:JSX 和 HTML 有什么区别? ​

HTMLJSX说明
classclassName避免和 JS class 冲突
forhtmlFor避免和 JS for 循环冲突
style="color: red"style={styleObj}接收对象字面量
onclickonClick驼峰命名
<br><br />必须闭合

Q3:为什么 v-for 需要 key? ​

key 帮助 React 识别列表中哪些元素变了,从而最小化 DOM 操作:

jsx
// ❌ 用 index 做 key,列表重排时会出错
{items.map((item, i) => <li key={i}>{item.name}</li>)}

// ✅ 用唯一 ID
{items.map(item => <li key={item.id}>{item.name}</li>)}

学习资源 ​