最近刚开始学 React,感觉组件化这东西有点像拼乐高,但一开始真的有点懵。今天就借着写 Todo 待办项目的经历,跟大家唠唠我这个新手的学习过程,可能说得不太专业,但都是自己踩过的坑和心得,希望能帮到同样刚开始的小伙伴。
第一步、先搭个架子
刚开始学的时候,听说要配置开发环境就头大。不过前辈推荐了 Vite,说是 “零配置快速启动”,试了一下真的很简单。就像点外卖一样,几步就能拿到一个现成的项目模板。
Vite 就像是一个现成的工具箱,里面装好了各种开发需要的工具,不用自己一点点配置。比如要创建一个 Todo 项目,只需要在命令行敲几行命令,它就会帮你生成好基本的项目结构,里面已经包含了 React 的基础配置,直接就能开工写代码。
# 跟着敲就能创建项目,超级简单
npm create vite@latest todoListComponents --template react
cd todoListComponents
npm install
npm run dev
这样一个能跑起来的项目就有了,里面的文件结构也很清晰,src
目录下是我们写代码的地方,组件可以放在 components
文件夹里,每个组件单独一个文件,看起来清清爽爽。
第二步、把页面分成小块
拿到一个页面,先别急着写代码,想想怎么把它拆分成小块。就拿 Todo 应用来说,一眼看去,页面上有标题、输入框、添加按钮、待办事项列表,这几个部分明显可以分开处理。在 React 里,每个部分都可以做成一个组件,就像把蛋糕切成几块,每块负责不同的功能。
比如:
- TodoList 组件:这是核心组件,就像一个大盒子,里面装着整个待办事项的逻辑,比如管理数据、协调其他组件。
- TodoForm 组件:专门负责输入框和添加按钮这部分,处理用户输入的内容。
- Todos 组件:只负责把待办事项列表显示出来,不用管其他逻辑。
- App 组件:作为最顶层的组件,就像一个总调度员,把 TodoList 组件放进去,页面就成型了。
function App() {
return (
<>
<TodoList />
</>
);
}
第三步、写函数组件
在 React 里,写组件最常用的方式是用函数。比如 TodoList 组件,就是一个普通的 JavaScript 函数,只不过这个函数会返回一段类似 HTML 的代码(JSX),告诉页面该长啥样。函数里面可以放变量、写逻辑,比传统的 HTML 模板灵活多了。
// TodoList.jsx 组件的核心代码
function TodoList() {
// 用 useState 来保存数据
const [todos, setTodos] = useState([{ id: 1, text: '吃饭', completed: false }]);
const [title, setTitle] = useState('Todo List');
// 处理添加待办事项的函数
const handleAdd = (text) => {
setTodos([...todos, { id: todos.length + 1, text, completed: false }]);
};
// 返回页面的结构
return (
<div className="container">
<h1>{title}</h1> {/* 直接把 title 变量放在大括号里,页面就会显示它的值 */}
<TodoForm onAdd={handleAdd} /> {/* 把 handleAdd 函数传给 TodoForm 组件,让它能调用 */}
<Todos todos={todos} /> {/* 把 todos 数据传给 Todos 组件,让它负责显示 */}
</div>
);
}
这里面的 useState
是个很关键的东西,它就像是一个开关,告诉 React 哪些数据是会变的,数据一变,页面就会自动刷新。比如上面的 todos
数组,里面存着所有待办事项,当我们添加新的事项时,调用 setTodos
改变这个数组,页面上的列表就会自动更新,不用自己去操作 DOM,省了很多麻烦。
第四步、让组件之间说话
组件之间不是孤立的,需要互相传递信息。比如 TodoForm 组件里的输入框,用户输入内容点击添加按钮后,需要把这个内容告诉 TodoList 组件,让它把新事项加到列表里。这时候就需要用到 props 和回调函数。
父组件给子组件传数据
TodoList 组件要把待办事项列表的数据传给 Todos 组件显示,怎么做呢?很简单,在调用 Todos 组件的时候,像这样写:<Todos todos={todos} />
,这里的 todos
就是 props,相当于把 todos
数组递给 Todos 组件。Todos 组件收到后,就可以用 props.todos
来拿到数据,然后循环渲染成列表:
// Todos.jsx 组件,负责显示列表
function Todos(props) {
const todos = props.todos; // 从 props 里取出 todos 数据
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>{todo.text}</li>
))}
</ul>
);
}
这里的 key
属性很重要,它就像每个列表项的身份证,告诉 React 哪个项是哪个,这样在列表更新时,React 就能快速找到变化的地方,避免不必要的重新渲染,提升性能。
子组件给父组件传消息
反过来,TodoForm 组件需要把用户输入的文本传给 TodoList 组件,这时候就需要父组件先给子组件传一个回调函数。比如在 TodoList 里,我们把 handleAdd
函数作为 props 传给 TodoForm:<TodoForm onAdd={handleAdd} />
,然后在 TodoForm 组件里,当用户提交表单时,调用这个函数,把文本传出去:
// TodoForm.jsx 组件,处理用户输入
function TodoForm(props) {
const [text, setText] = useState(''); // 保存输入框的内容
// 表单提交时的处理函数
const handleSubmit = (e) => {
e.preventDefault();
props.onAdd(text);
setText('');
};
const handleChange = (e) => {
setText(e.target.value)
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="请输入代办事项"
value={text}
onChange={handleChange}
/>
<button type="submit">添加</button>
</form>
);
}
这样一来,子组件就像是给父组件打了个电话,说 “我这里有新数据了”,父组件接到电话后,就可以处理数据,更新状态,页面也就跟着变了。这种方式很清晰,数据往哪流一看就明白,不会乱成一团。
通过上面的步骤,一个组件化的todo代办事项就做好了。
总结
作为新手,学 React 组件化的过程其实就是不断拆组件、传数据、处理状态的过程。刚开始可能会觉得麻烦,甚至搞不懂为什么要这么做,但写了几个小项目后,发现组件化真的能让代码更有条理,改起来也方便。
比如 Todo 项目里,每个组件只做一件事,TodoForm 只负责输入,Todos 只负责显示,TodoList 只负责管理数据,这样哪里出问题了,直接找对应的组件就行,不用在一堆代码里乱翻。而且组件还能复用,比如以后做其他项目需要输入框,直接把 TodoForm 拿过来改改就能用,节省了很多时间。
现在我还在学习阶段,可能理解得不够深,但感觉 React 组件化的核心就是 “分而治之”,把大问题拆成小问题,每个小问题用一个组件解决,最后像拼乐高一样组合起来。虽然中间会遇到很多坑,比如 props 传错名字、状态没更新、组件层级太深等等,但多写写代码,慢慢就会找到感觉。
最后,附上完整的代码结构,大家可以照着敲一敲,自己跑起来看看效果,边写边理解会更深刻:
看一看最终效果
希望这篇文章能让你对 React 组件化有更直观的理解,少走一些弯路,享受用组件搭积木的乐趣!