找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

2385

积分

0

好友

341

主题
发表于 前天 07:28 | 查看: 6| 回复: 0

抛开过时的教程,基于 Vite + React 18,手把手带你从零写出第一个组件。不讲虚的,全是干货!

引言:React 到底是个啥?

很多同学觉得 React 很难,学完就忘。其实,React 的核心思想非常简单,就三件事:

  1. 组件化:把页面像乐高积木一样,拆分成一个个独立的小块(组件)。
  2. JSX:允许你在 JavaScript 里写类似 HTML 的代码,所见即所得。
  3. 状态驱动:数据变了,界面自动变。你不需要手动去操作 DOM(比如 document.getElementById)。

只要搞懂这三点,你就入门了。废话少说,咱们直接开干!

第一步:环境搭建——告别黑盒,拥抱 Vite

很多新手被卡在第一步:环境配置。以前我们用 create-react-app (CRA),但现在 2025 年了,那个工具太慢了。

我们用新一代构建工具 Vite,快如闪电,3 分钟搞定环境。

打开你的终端,依次输入以下命令:

# 1. 使用 Vite 脚手架初始化项目
# 这里我们选择 React + TypeScript 模板 (推荐,大型项目更稳)
npm create vite@latest FullStackReactDemo -- --template react-ts
# 2. 进入项目文件夹
cd FullStackReactDemo
# 3. 安装依赖 (这就相当于给汽车加油)
npm i
# 4. 启动开发服务器 (点火!)
npm run dev

终端里会出现一行绿色的字:
➜ Local: http://localhost:5173/

打开浏览器,访问这个地址。如果看到 Vite 的 Logo 和旋转的 React 徽标,恭喜你,环境 OK 了!

第二步:Hello World——第一个 React 组件

现在,我们来创造点东西。

打开 src/App.tsx 文件。删掉里面默认的示例代码,我们写一个最简单的计数器。

修改 src/App.tsx

// 引入 React 核心的 useState Hook
import { useState } from 'react';
// 定义我们的根组件
function App() {
  // 1. 定义状态:count 是变量,setCount 是修改它的函数
  // 初始值为 0
  const [count, setCount] = useState(0);
  // 2. 返回 JSX 视图
  return (
    <div style={{ textAlign: 'center', marginTop: '60px' }}>
      <h1>你好,React 18!</h1>
      <p>当前计数:{count}</p>
      <button onClick={() => setCount(count + 1)}>
        +1
      </button>
    </div>
  );
}
export default App;

代码解析:

  • useState(0):这是 React 的一个 Hook(钩子)。它帮我们创建了一个“状态”变量 count。因为 React 要监控数据变化,所以不能像普通 JS 那样直接 let count = 0,必须用 setCount 来修改。
  • JSX:你看,我们在 return 里写了 HTML 标签。这就是 JSX。注意,class 要写成 className,因为这是 JavaScript 对象。
  • {count}:花括号里可以写任何 JavaScript 表达式。这里把变量 count 的值渲染到了页面上。

保存文件,浏览器会自动热更新。点一下按钮,数字是不是加 1 了?恭喜你,你已经掌握了 React 的核心:状态驱动视图!

第三步:实战 TodoList——组件化思维

光一个按钮太简单了。我们来搞个稍微复杂点的:待办事项列表 (Todo List)。这是检验前端入门的“黄金标准”。

我们要把页面拆成三个组件:

  1. App:根组件,负责管理所有数据。
  2. TodoInput:输入框组件,负责添加任务。
  3. TodoItem:单个任务项组件,负责显示和切换完成状态。

1. 定义数据结构 (TypeScript 的优势)

先在 src/App.tsx 顶部定义一下“待办事项”长什么样:

// 定义 Todo 的类型
export type Todo = {
  id: number;      // 唯一ID
  text: string;    // 任务内容
  done: boolean;   // 是否完成
};

2. 核心逻辑 (App.tsx)

修改 src/App.tsx 的内容:

import { useState } from 'react';
import TodoInput from './components/TodoInput';
import TodoList from './components/TodoList';
import type { Todo } from './App';

function App() {
  // 1. 状态:维护一个 todo 列表
  const [list, setList] = useState<Todo[]>([]);
  // 2. 逻辑:添加任务
  const addTodo = (text: string) => {
    const newItem: Todo = {
      id: Date.now(), // 简单粗暴用时间戳做ID
      text,
      done: false
    };
    // 不要直接修改 list,而是返回一个新数组
    setList([...list, newItem]);
  };
  // 3. 逻辑:切换任务完成状态
  const toggleTodo = (id: number) => {
    setList(
      list.map((todo) =>
        todo.id === id ? { ...todo, done: !todo.done } : todo
      )
    );
  };
  return (
    <div style={{ maxWidth: '400px', margin: '0 auto', padding: '20px' }}>
      <h2>极简 Todo </h2>
      {/* 2. 子组件:输入框,通过 onAdd 传递添加方法 */}
      <TodoInput onAdd={addTodo} />
      {/* 3. 子组件:列表,传递 list 数据和 toggle 方法 */}
      <TodoList todos={list} onToggle={toggleTodo} />
    </div>
  );
}
export default App;

3. 拆分组件:TodoInput

src 目录下新建 components 文件夹,创建 TodoInput.tsx

import { useState, KeyboardEvent } from 'react';
// 定义接收的属性类型
type Props = {
  onAdd: (text: string) => void;
};
export default function TodoInput({ onAdd }: Props) {
  const [val, setVal] = useState('');
  // 监听键盘事件,按回车添加
  const handleKey = (e: KeyboardEvent) => {
    if (e.key === 'Enter' && val.trim()) {
      onAdd(val.trim());
      setVal('');
    }
  };
  return (
    <input
      type="text"
      placeholder="按回车添加任务..."
      value={val}
      onChange={(e) => setVal(e.target.value)}
      onKeyDown={handleKey}
      style={{
        width: '100%',
        padding: '10px',
        marginBottom: '10px',
        border: '1px solid #ddd',
        borderRadius: '4px'
      }}
    />
  );
}

4. 拆分组件:TodoItem 和 TodoList

src/components/TodoItem.tsx (单个任务项):

import type { Todo } from '../App';
type Props = {
  todo: Todo;
  onToggle: (id: number) => void;
};
export default function TodoItem({ todo, onToggle }: Props) {
  return (
    <li
      onClick={() => onToggle(todo.id)}
      style={{
        cursor: 'pointer',
        padding: '8px 0',
        textDecoration: todo.done ? 'line-through' : 'none',
        color: todo.done ? '#888' : '#222',
        listStyle: 'none'
      }}
    >
      {todo.text}
    </li>
  );
}

src/components/TodoList.tsx (列表容器):

import type { Todo } from '../App';
import TodoItem from './TodoItem';
type Props = {
  todos: Todo[];
  onToggle: (id: number) => void;
};
export default function TodoList({ todos, onToggle }: Props) {
  if (todos.length === 0) return <p>暂无任务,快去添加一个吧~</p>;
  return (
    <ul style={{ padding: 0, listStyle: 'none' }}>
      {todos.map((todo) => (
        <TodoItem key={todo.id} todo={todo} onToggle={onToggle} />
      ))}
    </ul>
  );
}

结语:你已经入门了!

停一下手里的活儿,看看浏览器。

输入文字,按回车,任务出现了!点一下任务,它划掉了!这可是 Facebook 开源的 React 核心思想在你手里的完美体现!

咱们回顾一下这 30 分钟干了啥:

  1. 搭环境:用 Vite 3 分钟跑通开发环境,掌握了现代 前端工程化 的起点。
  2. 写组件:学会了函数式组件和 JSX 语法。
  3. 管状态:用 useState 实现了数据驱动视图。
  4. 组件通信:父组件 (App) 通过 props 把数据和方法传给子组件 (TodoInput, TodoItem)。

接下来的学习建议:

  • useEffect:处理副作用(比如页面加载时去请求数据)。
  • 学路由 (React Router):实现页面跳转。
  • 学状态管理 (Redux Toolkit / Zustand):当组件越来越多,数据传递很麻烦时用。

React 并不难,难的是迈出第一步。现在,你已经迈出去了。如果想深入学习更多实用的 技术文档 与实战项目,欢迎来 云栈社区 交流探讨。




上一篇:Linux内存映射(mmap)机制详解:从原理到高性能应用实践
下一篇:2026年前端开发者值得期待的CSS新特性:原生布局与动效革新
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-1-14 16:00 , Processed in 0.405854 second(s), 39 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2025 云栈社区.

快速回复 返回顶部 返回列表