从零开始学 React:这些核心知识点你必须掌握
大家好啊!今天咱们来聊聊 React—— 这个现在前端圈超火的库。不管你是刚入门前端的小白,还是想转行学开发的新手,只要想做界面开发,React 几乎是绕不开的坎。别担心,今天我就用最接地气的话,把 React 每天要用的 80% 核心知识点讲透,每个点都配代码,保证你看完就懂,懂了就能用!
一、创建和嵌套组件:React 的 “积木块”
咱们先从最基础的说起:组件。你可以把组件理解成 UI 的 “积木”,小到一个按钮,大到一整个页面,都是组件拼出来的。
重点总结:
- 组件是返回标签的 JavaScript 函数
- 组件名必须以大写字母开头(区分 HTML 标签)
- 组件可以像积木一样嵌套使用
咱们来看个例子,先创建一个按钮组件:
function MyButton() {
return (
<button>I'm a button</button>
);
}
这个MyButton就是个最简单的组件,它是个函数,返回了一个按钮标签。注意哦,函数名MyButton是大写开头的,这是规矩,要是写成小写myButton,React 就不认识它是组件了。
那怎么用这个组件呢?可以把它嵌套到另一个组件里,比如整个应用的根组件:
export default function MyApp() {
return (
<div>
<h1>Welcome to my app</h1>
<MyButton /> {/* 嵌套刚才创建的MyButton组件 */}
</div>
);
}
这里的export default是说,MyApp是这个文件里的 “主角” 组件,其他地方导入这个文件时,默认拿到的就是它。
你看,这样就像搭积木一样,用<MyButton />把按钮组件拼到了MyApp里,运行起来就会显示 “Welcome to my app” 和一个按钮。是不是很简单?
二、用 JSX 写标签:React 的 “专属语法”
刚才写的<button>、<div>这种标签,其实不是 HTML,而是JSX语法。它是 React 推荐的写标签的方式,虽然不是必须的,但用起来是真方便。
重点总结:
- JSX 是 React 里写标签的语法,融合了 JS 和 HTML
- 必须闭合所有标签(比如
<br />不能写成<br>) - 组件不能返回多个 JSX 标签,必须用一个父级包起来(比如
<div>或<>)
JSX 比 HTML 严格多了。比如 HTML 里<img src="xxx">可以不闭合,但 JSX 里必须写成<img src="xxx" />。再比如,一个组件想返回多个标签,直接写是不行的:
// 错误示例:不能返回多个标签
function AboutPage() {
return (
<h1>About</h1>
<p>Hello there.</p> {/* 这里会报错! */}
);
}
这时候就得找个 “容器” 把它们包起来。可以用<div>:
function AboutPage() {
return (
<div> {/* 用div当容器 */}
<h1>About</h1>
<p>Hello there.<br /></p> {/* <br />必须闭合 */}
</div>
);
}
要是不想多一个<div>(有时候会影响样式或布局),可以用空标签<>(也叫 Fragment):
function AboutPage() {
return (
<> {/* 空标签当容器,不产生额外DOM */}
<h1>About</h1>
<p>Hello there.<br /></p>
</>
);
}
这样既满足了 “一个父级” 的要求,又不会多出来没用的标签,完美!
如果手里有一堆 HTML 想转成 JSX,不用手动改,网上有现成的在线转换器,复制粘贴就行,超方便。
三、给组件加样式:让界面变好看
写好了结构,接下来就得打扮打扮组件了。React 里加样式的方式和 HTML 很像,但有一点点区别。
重点总结:
- 用
className指定 CSS 类(相当于 HTML 的class) - 可以用
style属性写行内样式,适合依赖 JS 变量的情况 - CSS 文件该怎么引入还怎么引入(比如用
<link>标签)
先看用 CSS 类的方式。比如想给图片加个圆形边框,先在 JSX 里用className定义类名:
<img className="avatar" /> {/* 注意是className,不是class */}
然后在 CSS 文件里写样式:
/* 比如叫style.css */
.avatar {
border-radius: 50%; /* 圆形边框 */
}
最后在 HTML 里用<link>引入这个 CSS 文件就行,和普通网页一样。
那如果样式需要根据 JS 变量动态变化呢?这时候就用style属性。比如图片大小由变量imageSize决定:
const user = {
name: 'Hedy Lamarr',
imageUrl: 'https://i.imgur.com/yXOvdOSs.jpg',
imageSize: 90, // 图片大小
};
function Profile() {
return (
<>
<h1>{user.name}</h1>
<img
className="avatar" // 用CSS类
src={user.imageUrl}
alt={'Photo of ' + user.name}
style={{ // 行内样式,注意是双大括号
width: user.imageSize, // 依赖JS变量
height: user.imageSize
}}
/>
</>
);
}
这里的style={{}}其实是style={}(JSX 大括号)里面包了一个普通的 JS 对象{},所以是双大括号。这种方式适合样式跟着变量变的场景,比如根据状态改颜色、大小等。
四、显示数据:让 JS 和标签 “互动”
React 的一大优势就是能轻松把 JS 里的数据显示到界面上。秘诀就是用大括号{}—— 在 JSX 里,大括号就像一个 “通道”,能把 JS 变量或表达式 “送” 到标签里。
重点总结:
- 用
{变量名}在 JSX 中显示数据 - 属性里用
{}而不是引号(引号里是字符串,{}里是 JS 表达式) - 大括号里可以写任何 JS 表达式(比如字符串拼接、运算等)
比如想显示用户名字,直接把user.name放进大括号:
return <h1>{user.name}</h1>; // 显示user对象的name属性
如果是标签的属性,比如图片的src,也用大括号:
// 正确:用{}引用JS变量
<img src={user.imageUrl} />
// 错误:引号里的是字符串,不会解析变量
<img src="user.imageUrl" /> {/* 会把"user.imageUrl"当字符串,显示不了图片 */}
大括号里还能写更复杂的表达式,比如字符串拼接:
alt={'Photo of ' + user.name} // 拼接成"Photo of Hedy Lamarr"
甚至可以写运算,比如显示数字加 1:
<p>Count: {count + 1}</p> // 如果count是3,就显示"Count: 4"
这样一来,JS 里的数据就能随时 “同步” 到界面上,特别灵活。
五、条件渲染:让界面 “看情况” 显示
有时候界面需要根据条件显示不同内容,比如用户登录了显示 “欢迎回来”,没登录显示 “请登录”。React 里没有专门的条件语法,直接用普通 JS 的 if、三元运算符就行。
重点总结:
- 用 if 语句拆分不同条件的 JSX
- 用
条件 ? 内容1 : 内容2在 JSX 内写条件 - 用
条件 && 内容只在条件为真时显示内容
先看 if 语句的用法。比如根据isLoggedIn(是否登录)显示不同组件:
let content; // 存储要显示的内容
if (isLoggedIn) {
content = <AdminPanel />; // 登录了显示管理面板
} else {
content = <LoginForm />; // 没登录显示登录表单
}
return <div>{content}</div>; // 显示content
这种方式适合条件比较复杂的情况,逻辑清晰。
如果想写得更紧凑,可以用三元运算符,直接嵌在 JSX 里:
<div>
{isLoggedIn ? ( // 条件
<AdminPanel /> // 条件为真时显示
) : (
<LoginForm /> // 条件为假时显示
)}
</div>
这样不用单独定义变量,一行搞定。
还有一种更简单的情况:只在条件为真时显示内容,否则不显示。这时候用&&运算符:
<div>
{isLoggedIn && <AdminPanel />} // 只有isLoggedIn为真,才显示AdminPanel
</div>
原理是 JS 里true && 表达式会返回表达式,false && 表达式会返回 false,而 React 会忽略 false,所以不显示。
比如购物清单里,只给水果标上特殊颜色,就可以这么写:
const products = [
{ title: 'Cabbage', isFruit: false, id: 1 },
{ title: 'Garlic', isFruit: false, id: 2 },
{ title: 'Apple', isFruit: true, id: 3 },
];
function ShoppingList() {
const listItems = products.map(product => (
<li
key={product.id}
style={{
color: product.isFruit ? 'magenta' : 'darkgreen' // 三元运算符:水果是洋红色,蔬菜是深绿色
}}
>
{product.title}
</li>
));
return <ul>{listItems}</ul>;
}
这里根据product.isFruit的真假,用三元运算符动态改颜色,是不是很灵活?
五、渲染列表:批量展示数据
网页里经常要显示列表(比如商品列表、评论列表),React 里渲染列表的关键是用 JS 的map()函数 —— 把数组里的每个元素转成 JSX 标签,再整体显示。
重点总结:
- 用
array.map()把数组转成 JSX 列表 - 每个列表项必须有
key属性,且唯一(通常用数据的 id) key帮助 React 识别列表项的变化,提升性能
比如有个产品数组,想渲染成<li>列表:
const products = [
{ title: 'Cabbage', id: 1 },
{ title: 'Garlic', id: 2 },
{ title: 'Apple', id: 3 },
];
function ShoppingList() {
// 用map把数组转成li标签数组
const listItems = products.map(product => (
<li
key={product.id} // 必须有key,且唯一
>
{product.title}
</li>
));
return <ul>{listItems}</ul>; // 显示列表
}
这里的key非常重要,它就像列表项的 “身份证”,React 靠它判断哪个项被添加、删除或修改了,从而高效更新界面。key必须在兄弟项之间唯一,最好用数据本身的 id(比如从数据库拿的 id),不要用数组索引(因为索引会变)。
再加点样式,让水果和蔬菜颜色不同(前面条件渲染的例子):
const products = [
{ title: 'Cabbage', isFruit: false, id: 1 },
{ title: 'Garlic', isFruit: false, id: 2 },
{ title: 'Apple', isFruit: true, id: 3 },
];
function ShoppingList() {
const listItems = products.map(product => (
<li
key={product.id} // 唯一key
style={{
color: product.isFruit ? 'magenta' : 'darkgreen' // 动态颜色
}}
>
{product.title}
</li>
));
return <ul>{listItems}</ul>;
}
这样渲染出来的列表,苹果是洋红色,白菜和大蒜是深绿色,清晰又直观。
六、响应事件:让组件 “有反应”
界面不能只是 “看” 的,还得能 “互动”—— 比如点击按钮、输入文字等。React 里通过事件处理函数来响应这些操作。
重点总结:
- 用
on事件名(比如onClick)绑定事件处理函数 - 事件处理函数是普通 JS 函数,定义在组件内部
- 绑定的时候不要加括号(
onClick={handleClick},不是handleClick())
比如做个按钮,点击弹出提示:
function MyButton() {
// 定义事件处理函数
function handleClick() {
alert('You clicked me!'); // 点击后执行
}
return (
<button onClick={handleClick}> // 绑定事件,注意没有括号
Click me
</button>
);
}
这里的onClick是 React 的点击事件(注意首字母大写,和 HTML 的onclick不同),等号后面是事件处理函数handleClick。特别注意:不要写成onClick={handleClick()}—— 加了括号会立即执行函数,而不是等点击的时候执行。
除了点击事件,还有onChange(输入变化)、onSubmit(表单提交)等,用法都一样:定义函数,然后绑定到on事件名上。比如输入框内容变化时打印值:
function MyInput() {
function handleChange(e) {
console.log('输入的是:', e.target.value); // e是事件对象
}
return (
<input
type="text"
onChange={handleChange} // 输入变化时触发
/>
);
}
这样每次输入文字,控制台都会打印当前输入的内容,轻松实现互动。
七、更新界面:让组件 “记住” 状态
很多时候,组件需要 “记住” 一些信息并更新界面 —— 比如按钮被点击了多少次。这时候就需要state(状态),它是组件内部的 “记忆”,状态变了,界面会自动更新。
重点总结:
- 用
useState声明状态变量(需要从 React 导入) useState(初始值)返回两个东西:当前状态和更新状态的函数(比如[count, setCount])- 调用更新函数(比如
setCount)会改变状态,并让组件重新渲染
先看个计数器的例子:点击按钮,次数加 1。步骤很简单:
- 从 React 导入
useState:
import { useState } from 'react'; // 第一步:导入
- 在组件里用
useState声明状态变量:
function MyButton() {
// 声明count状态,初始值是0
// count是当前状态,setCount是更新它的函数
const [count, setCount] = useState(0);
- 写事件处理函数,用
setCount更新状态:
function handleClick() {
setCount(count + 1); // 点击一次,count加1
}
- 在 JSX 里显示
count:
return (
<button onClick={handleClick}>
Clicked {count} times // 显示当前次数
</button>
);
}
完整代码就是:
import { useState } from 'react';
function MyButton() {
const [count, setCount] = useState(0);
function handleClick() {
setCount(count + 1);
}
return (
<button onClick={handleClick}>
Clicked {count} times
</button>
);
}
运行后,每次点击按钮,count会加 1,界面上的次数也会跟着变。这就是 state 的魔力:状态变了,React 会自动重新渲染组件,让界面展示最新的状态。
更厉害的是,每个组件的 state 都是独立的。比如渲染两个MyButton:
export default function MyApp() {
return (
<div>
<MyButton />
<MyButton />
</div>
);
}
点击第一个按钮,只有第一个的次数会增加;点击第二个,只有第二个的次数会增加 —— 它们各记各的,互不影响。
八、使用 Hook:React 的 “功能插件”
刚才用的useState其实是一个Hook(钩子)。Hook 是 React 里一类特殊的函数,能让组件拥有各种功能(比如 state、副作用等),名字都以use开头。
重点总结:
- Hook 是 React 的功能函数,以
use开头(如useState、useEffect) - 只能在组件的顶层调用 Hook(不能在 if、循环、函数嵌套里用)
- 可以自己组合 Hook 创建自定义 Hook
useState是最常用的内置 Hook,用来管理状态。还有个常用的useEffect,用来处理副作用(比如请求数据、设置定时器),不过这里先不展开,知道有这么个东西就行。
使用 Hook 有个严格的规则:只能在组件的顶层调用,不能在条件、循环或嵌套函数里用。比如下面的代码是错误的:
// 错误示例:在if里调用useState
function MyComponent() {
if (someCondition) {
const [count, setCount] = useState(0); // 不行!
}
// ...
}
为什么呢?因为 React 靠 Hook 的调用顺序来管理它们,如果在条件里调用,顺序会乱,导致 bug。如果确实需要条件判断,就把 Hook 提到条件外面,或者拆分成新组件。
除了内置 Hook,还能自己写自定义 Hook,把重复的逻辑抽出来。比如多个组件都需要 “记录点击次数” 的功能,就可以写个useCounter Hook:
import { useState } from 'react';
// 自定义Hook,以use开头
function useCounter(initialValue) {
const [count, setCount] = useState(initialValue);
function increment() {
setCount(count + 1);
}
return [count, increment]; // 返回状态和更新函数
}
// 使用自定义Hook
function MyButton() {
const [count, increment] = useCounter(0); // 复用逻辑
return (
<button onClick={increment}>
Clicked {count} times
</button>
);
}
这样一来,任何组件想实现计数器功能,直接用useCounter就行,不用重复写useState和increment逻辑了,特别方便。
九、组件间共享数据:让组件 “协同工作”
有时候多个组件需要共享数据,比如两个按钮,点击任何一个,两个按钮显示的次数都一起增加。这时候就需要状态提升—— 把共享的状态放到它们共同的父组件里,再通过 props 传递给子组件。
重点总结:
- 状态提升:子组件的状态移到父组件,通过 props 传递给子组件
- props 是父组件传递给子组件的数据 / 函数,子组件通过参数接收
- 子组件通过调用父组件传递的函数,间接更新父组件的状态
还用计数器的例子,现在要两个按钮共享一个 count,点击任何一个,次数一起增加。步骤如下:
- 把状态从子组件
MyButton移到父组件MyApp:
import { useState } from 'react';
export default function MyApp() {
// 父组件里声明状态
const [count, setCount] = useState(0);
// 父组件里定义更新函数
function handleClick() {
setCount(count + 1);
}
return (
<div>
<h1>Counters that update together</h1>
{/* 把count和handleClick传给子组件 */}
<MyButton count={count} onClick={handleClick} />
<MyButton count={count} onClick={handleClick} />
</div>
);
}
- 子组件
MyButton通过参数接收父组件传递的count和onClick(这些参数叫 props):
// 子组件接收props
function MyButton({ count, onClick }) {
return (
<button onClick={onClick}> // 调用父组件的函数
Clicked {count} times // 显示父组件传递的count
</button>
);
}
这样一来,两个MyButton的count都来自父组件的count,点击时调用的都是父组件的handleClick,所以不管点哪个,父组件的count都会增加,两个按钮显示的次数也会一起更新。
这种 “状态提升” 是 React 中组件共享数据的核心方式:共享的数据放在共同的父组件,子组件通过 props 获取数据和更新方法,实现协同工作。
总结:React 入门就这么点事儿
看到这里,你已经掌握了 React 日常开发中 80% 的知识点:从创建组件、写 JSX 标签,到加样式、显示数据,再到处理事件、管理状态、共享数据,一套流程走下来,基本能写个简单的 React 应用了。
可能一开始会觉得 JSX、state、props 这些概念有点绕,但多写几个例子就会发现,它们其实都是为了让 “数据” 和 “界面” 更好地配合。组件就像积木,state 是记忆,props 是桥梁,事件是互动的开关,把这些串起来,就能搭出各种复杂的界面。
接下来建议你找个小项目练练手,比如 todo 列表、计数器、简单的表单,把这些知识点用起来。用着用着就会发现,React 其实没那么难,甚至还挺有趣的!
如果想深入学习,可以看看 React 官方文档的 “实战教程”,或者研究更复杂的 Hook(比如useEffect、useContext),但入门阶段,把今天讲的这些吃透,就足够应付大部分场景了。加油,祝你在 React 的路上越走越顺!
更多推荐
所有评论(0)