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" danger width: '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 [currentPage, setCurrentPage] = 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 [loading, setLoading] = 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()[0].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、三元运算符、&&)实现。
国内项目示例:多场景条件渲染(覆盖高频需求)
[code]import React, { useState, useEffect } from 'react';import { Spin, Empty, List, Avatar } from 'antd';const MessageList = () => { // 状态:加载中、消息数据、是否登录 const [loading, setLoading] = useState(true); const [messages, setMessages] = useState([]); const [isLogin, setIsLogin] = 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 ? ( ( |