React 基础核心概念(8 个)——从入门到能写业务组件(上)| 葡萄城技术团队
React 基础核心概念(8 个)——从入门到能写业务组件(上)前言:为什么要先掌握这些基础概念?
对国内开发者来说,React 是开发中后台系统、电商前端、移动端 H5 的“刚需技能”。但很多人刚学就陷入“会写 JSX 却不懂原理”的困境——比如不知道为什么状态更新后页面不刷新,或者写组件时反复遇到“属性透传”的麻烦。
这篇整理的 8 个基础概念,是 React 开发的“地基”:从 JSX 语法到最常用的 Hooks,每个都配了国内项目常见的示例(比如商品列表渲染、用户登录状态管理),帮你跳过“照抄代码却不懂逻辑”的坑,真正能独立写业务组件。
1. 什么是 React 中的 JSX?搞懂 React 专属语法
定义与作用
JSX(JavaScript XML)是 React 的“模板语法”,允许你在 JS 代码里写类似 HTML 的结构。很多初学者以为它是“HTML 的变体”,其实它最终会被 Babel 编译成React.createElement()函数,生成 React 元素(虚拟 DOM 节点)。
国内开发场景中,JSX 是写组件的“标配”——无论是电商的商品卡片,还是后台的表格组件,都靠 JSX 描述 UI 结构。
国内项目示例:电商商品卡片(JSX 实战)
import React from 'react';
// 引入国内常用的UI组件库(如Ant Design)
import { Card, Button, Tag } from 'antd';
// 商品卡片组件:接收商品数据作为props
const ProductCard = ({ product }) => {
const { id, name, price, stock, isDiscount } = product;
return (
// JSX支持嵌入JS表达式(用{}包裹)
<card key="{id}" title="{name}" cover="{<img" src="https://www.cnblogs.com/{`/images/products/${id}.jpg`}" alt="{name}" />}
style={{ width: 240, margin: '16px' }} // 行内样式需用对象(驼峰命名)
>
{/* 条件渲染标签:有折扣显示“限时折扣” */}
{isDiscount && <tag color="red">限时折扣</tag>}
¥{price.toFixed(2)}
库存:{stock}件
{/* 事件绑定:点击按钮添加购物车(后续会讲事件处理) */}
<button type="primary" dangerwidth: '100%', margintop: 12 }} onclick="{()" => console.log(`添加商品 ${name} 到购物车`)}
>
加入购物车
</button>
);
};
// 使用组件:传入国内电商常见的商品数据
const ProductList = () => {
const products = [
{ id: 1, name: '华为Mate 60 Pro', price: 6999, stock: 120, isDiscount: false },
{ id: 2, name: '小米14', price: 4999, stock: 86, isDiscount: true },
];
return (
{products.map(product => <productcard product="{product}" />)}
);
};
export default ProductList;注意点(国内开发者常踩的坑)
[*]不能直接写class:需用className(因为class是 JS 关键字);
[*]自闭合标签必须写/:比如,不像 HTML 里可以省略;
[*]只能有一个根节点:如果有多个元素,需用或(简写<>)包裹。
2. React 中的 State 与 Props:组件的“数据传递与状态管理”核心
定义与区别
[*]Props(属性):父组件传给子组件的数据,类似“函数参数”,只读不可改(子组件不能直接修改 props);
[*]State(状态):组件内部管理的“动态数据”(如输入框内容、弹窗显示/隐藏),可修改但需用 setter 方法(如setCount),修改后会触发组件重新渲染。
国内开发中,这两者是“父子组件通信”和“组件内部状态控制”的核心——比如后台管理系统中,父组件传“表格数据”给子表格组件(用 props),子组件内部管理“分页页码”(用 state)。
国内项目示例:后台表格组件(State 与 Props 结合)
import React, { useState } from 'react';
import { Table, Pagination } from 'antd';
// 子组件:表格(接收父组件传的props)
const DataTable = ({ tableData, columns }) => {
// 子组件内部状态:当前页码(只能自己修改)
const = useState(1);
// 每页条数(国内后台常用10/20/50条)
const pageSize = 10;
// 处理页码变化(子组件内部更新state)
const handlePageChange = (page) => {
setCurrentPage(page);
};
// 分页逻辑:截取当前页数据
const currentData = tableData.slice(
(currentPage - 1) * pageSize,
currentPage * pageSize
);
return (
{/* 表格:用props传的columns和处理后的currentData */}
<table columns="{columns}" dataSource="{currentData}" rowKey="id" pagination="{false}" 关闭表格自带分页,用自定义分页></table>
{/* 分页组件:状态currentPage控制显示 */}
<pagination current="{currentPage}" pageSize="{pageSize}" total="{tableData.length}" onChange="{handlePageChange}"marginTop: 16, textAlign: 'right' }} />
);
};
// 父组件:使用表格(传props给子组件)
const UserManagePage = () => {
// 父组件数据:用户列表(模拟接口返回的国内后台数据)
const userColumns = [
{ title: '用户ID', dataIndex: 'id', key: 'id' },
{ title: '用户名', dataIndex: 'username', key: 'username' },
{ title: '角色', dataIndex: 'role', key: 'role' },
{ title: '状态', dataIndex: 'status', key: 'status', render: (status) => status ? '启用' : '禁用' },
];
const userData = [
{ id: 1, username: 'zhangsan', role: '管理员', status: true },
{ id: 2, username: 'lisi', role: '普通用户', status: true },
// ... 更多数据
];
// 父组件传给子组件的props:tableData和columns
return <datatable tableData="{userData}" columns="{userColumns}" />;
};
export default UserManagePage;3. React 事件处理:和原生 JS 有啥不一样?
核心特点
React 的“合成事件”(SyntheticEvent)是对原生 DOM 事件的封装,目的是解决“跨浏览器兼容”问题——国内开发者不用再写addEventListener兼容 IE,直接用onClick这类驼峰命名的事件即可。
另外,React 事件处理有两个关键点:
[*]事件处理函数需要“正确绑定 this”(类组件中常见,函数组件用箭头函数可避免);
[*]传参时需用“函数包裹”(如onClick={() => handleDelete(id)}),避免直接执行函数。
国内项目示例:表单提交与按钮点击(高频场景)
import React, { useState } from 'react';
import { Form, Input, Button, message } from 'antd';
const LoginForm = () => {
const = useState(false); // 登录加载状态
// 1. 表单提交事件(带参数,需用箭头函数包裹)
const handleSubmit = async (values) => {
setLoading(true); // 点击提交后显示加载状态
try {
// 模拟国内接口请求(如调用后端登录接口)
const res = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(values),
});
const data = await res.json();
if (data.success) {
message.success('登录成功!');
// 跳转到首页(国内常用react-router)
// navigate('/home');
} else {
message.error(data.message || '登录失败');
}
} catch (error) {
message.error('网络错误,请重试');
} finally {
setLoading(false); // 无论成功失败,关闭加载状态
}
};
// 2. 普通按钮点击事件(无参数)
const handleReset = () => {
// 重置表单(Ant Design Form方法)
Form.useForm().resetFields();
};
return (
<form name="login_form" layout="vertical" onFinish="{handleSubmit}" 表单提交事件(React合成事件)width: 350, margin: '0 auto' }}>
<form.item name="username" label="用户名" rules="{[{" required: true, message: '请输入用户名' }]}>
<input placeholder="请输入用户名">
</form.item>
<form.item name="password" label="密码" rules="{[{" required: true, message: '请输入密码' }]}>
<input.password placeholder="请输入密码" />
</form.item>
<form.item>
<button type="primary" htmltype="submit" loading="{loading}"marginright: 8 }}>
登录
</button>
<button onclick="{handleReset}">重置</button>
</form.item>
</form>
);
};
export default LoginForm;4. React 条件渲染:怎么优雅地控制 UI 显示?
核心场景
国内开发中,条件渲染几乎无处不在:用户登录/未登录显示不同按钮、接口请求中显示“加载中”、数据为空显示“暂无数据”……React 没有专门的“条件渲染语法”,而是用 JS 的逻辑(如if-else、三元运算符、&&)实现。
国内项目示例:多场景条件渲染(覆盖高频需求)
import React, { useState, useEffect } from 'react';import { Spin, Empty, List, Avatar } from 'antd';const MessageList = () => {// 状态:加载中、消息数据、是否登录const = useState(true);const = useState([]);const = useState(false);// 模拟接口请求(国内后台常见的“消息列表”接口)useEffect(() => { const fetchMessages = async () => { try { const res = await fetch('/api/messages'); const data = await res.json(); setMessages(data.list); setIsLogin(data.isLogin); // 接口返回登录状态 } catch (error) { console.error('获取消息失败:', error); } finally { setLoading(false); } }; fetchMessages();}, []);// 1. 加载中:显示Spin组件(国内常用加载组件)if (loading) { return ;}// 2. 未登录:显示“请登录”提示(三元运算符)if (!isLogin) { return ( 请先登录查看消息
setIsLogin(true)}> 立即登录 );}return ( 我的消息
{/* 3. 有消息:渲染列表(&& 语法) */} {messages.length > 0 ? ( (
页:
[1]