React基础:语法、组件与JSX
一、JSX基础
1. 什么是JSX?
// JSX是JavaScript的语法扩展
const element = <h1>Hello, World!</h1>;
// 编译为普通的JavaScript
// 实际是:const element = React.createElement('h1', null, 'Hello, World!');
2. JSX表达式
function App() {
const name = "后端开发者";
const isLoggedIn = true;
const user = { firstName: "John", lastName: "Doe" };
return (
<div>
{/* 1. 嵌入变量 */}
<h1>Hello, {name}</h1>
{/* 2. 条件渲染 */}
{isLoggedIn ? (
<p>欢迎回来!</p>
) : (
<p>请先登录</p>
)}
{/* 3. 调用函数 */}
<p>用户名: {getFullName(user)}</p>
{/* 4. 嵌入HTML */}
<div dangerouslySetInnerHTML={{ __html: "<span>注意:谨慎使用</span>" }} />
</div>
);
}
function getFullName(user) {
return `${user.firstName} ${user.lastName}`;
}
二、组件基础
1. 函数组件(推荐)
// 最简单的函数组件
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
// 使用箭头函数
const Button = ({ onClick, children }) => {
return (
<button onClick={onClick} style={{ padding: '10px 20px' }}>
{children}
</button>
);
};
2. Props(属性)
// 定义带默认值的组件
function UserCard({
name,
role = "开发者", // 默认值
age,
isActive = false
}) {
return (
<div className={`user-card ${isActive ? 'active' : ''}`}>
<h2>{name}</h2>
<p>职位: {role}</p>
{age && <p>年龄: {age}岁</p>}
<p>状态: {isActive ? '在线' : '离线'}</p>
</div>
);
}
// 使用组件
function App() {
return (
<div>
<UserCard name="张三" role="后端工程师" age={28} isActive={true} />
<UserCard name="李四" /> {/* 使用默认值 */}
</div>
);
}
3. 组件组合
// 容器组件
function UserDashboard() {
const users = [
{ id: 1, name: 'Alice', role: 'Admin' },
{ id: 2, name: 'Bob', role: 'User' },
];
return (
<div className="dashboard">
<Header title="用户管理系统" />
<UserList users={users} />
<Footer year={2024} />
</div>
);
}
// 子组件
function Header({ title }) {
return (
<header>
<h1>{title}</h1>
<nav>
<a href="/users">用户</a>
<a href="/settings">设置</a>
</nav>
</header>
);
}
function UserList({ users }) {
return (
<ul>
{users.map(user => (
<li key={user.id}>
<UserItem user={user} />
</li>
))}
</ul>
);
}
三、事件处理
function InteractiveComponent() {
// 点击事件
const handleClick = (event, message) => {
console.log('点击事件:', message);
console.log('事件对象:', event);
event.preventDefault(); // 阻止默认行为
};
// 表单输入事件
const handleChange = (event) => {
console.log('输入值:', event.target.value);
};
// 表单提交事件
const handleSubmit = (event) => {
event.preventDefault();
const formData = new FormData(event.target);
const data = Object.fromEntries(formData);
console.log('表单数据:', data);
};
return (
<div>
{/* 点击事件 */}
<button onClick={(e) => handleClick(e, '按钮被点击')}>
点击我
</button>
{/* 输入事件 */}
<input
type="text"
onChange={handleChange}
placeholder="输入文本..."
/>
{/* 表单提交 */}
<form onSubmit={handleSubmit}>
<input name="username" placeholder="用户名" />
<input name="email" type="email" placeholder="邮箱" />
<button type="submit">提交</button>
</form>
</div>
);
}
四、条件渲染
function ConditionalRendering() {
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [showDetails, setShowDetails] = useState(false);
// 1. if-else条件渲染
const renderContent = () => {
if (isLoading) {
return <Spinner />;
}
if (error) {
return <ErrorMessage error={error} />;
}
if (data) {
return <DataDisplay data={data} />;
}
return <EmptyState />;
};
return (
<div>
{/* 2. 三目运算符 */}
<div>
{isLoading ? <Spinner /> : <Content data={data} />}
</div>
{/* 3. 逻辑与运算符(短路计算) */}
{!isLoading && data && (
<div>
<h2>数据加载完成</h2>
<p>共 {data.length} 条记录</p>
</div>
)}
{/* 4. 立即执行函数 */}
{(() => {
if (showDetails) {
return <DetailsPanel />;
}
return null;
})()}
{/* 切换显示状态 */}
<button onClick={() => setShowDetails(!showDetails)}>
{showDetails ? '隐藏详情' : '显示详情'}
</button>
{/* 5. 条件组件渲染 */}
{renderContent()}
</div>
);
}
五、列表渲染
function ListRendering() {
// 模拟API返回的数据
const users = [
{ id: 1, name: 'Alice', email: 'alice@example.com', role: 'admin' },
{ id: 2, name: 'Bob', email: 'bob@example.com', role: 'user' },
{ id: 3, name: 'Charlie', email: 'charlie@example.com', role: 'user' },
];
const posts = [
{ id: 101, title: 'React入门', author: 'Alice', likes: 42 },
{ id: 102, title: '后端开发', author: 'Bob', likes: 28 },
];
return (
<div>
{/* 1. 基本列表渲染 */}
<h2>用户列表</h2>
<ul>
{users.map(user => (
<li key={user.id}>
{user.name} ({user.email})
</li>
))}
</ul>
{/* 2. 带条件的列表渲染 */}
<h2>管理员列表</h2>
<ul>
{users
.filter(user => user.role === 'admin')
.map(user => (
<li key={user.id}>
{user.name} - 管理员
</li>
))
}
</ul>
{/* 3. 渲染复杂组件 */}
<h2>文章列表</h2>
<div className="post-list">
{posts.map(post => (
<PostItem
key={post.id}
post={post}
onLike={() => console.log('点赞:', post.id)}
/>
))}
</div>
{/* 4. 没有数据的情况 */}
{users.length === 0 && (
<p>暂无用户数据</p>
)}
</div>
);
}
// 列表项组件
function PostItem({ post, onLike }) {
return (
<div className="post-item">
<h3>{post.title}</h3>
<p>作者: {post.author}</p>
<div>
<span>👍 {post.likes}</span>
<button onClick={onLike}>点赞</button>
</div>
</div>
);
}
六、样式处理
function StylingExamples() {
// 1. 内联样式(对象形式)
const headerStyle = {
backgroundColor: '#282c34',
color: 'white',
padding: '20px',
borderRadius: '8px',
};
// 2. 动态样式
const [isActive, setIsActive] = useState(false);
const buttonStyle = {
padding: '10px 20px',
backgroundColor: isActive ? '#4CAF50' : '#f0f0f0',
color: isActive ? 'white' : '#333',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
transition: 'all 0.3s ease',
};
return (
<div>
{/* 内联样式 */}
<div style={headerStyle}>
<h1>样式示例</h1>
</div>
{/* 动态样式 */}
<button
style={buttonStyle}
onClick={() => setIsActive(!isActive)}
>
{isActive ? '激活中' : '未激活'}
</button>
{/* CSS类名 */}
<div className="card success">
<p>使用CSS类的组件</p>
</div>
{/* 动态类名 */}
<div className={`alert ${isActive ? 'alert-active' : 'alert-inactive'}`}>
动态类名示例
</div>
{/* 行内样式 */}
<div style={{
margin: '20px 0',
padding: '15px',
border: '1px solid #ddd',
boxShadow: '0 2px 4px rgba(0,0,0,0.1)',
}}>
直接在JSX中写样式
</div>
</div>
);
}
七、基础组件示例
// 1. 可复用的按钮组件
function CustomButton({
variant = 'primary', // 'primary' | 'secondary' | 'danger'
size = 'medium', // 'small' | 'medium' | 'large'
onClick,
children,
disabled = false,
loading = false
}) {
const baseClasses = 'custom-button';
const variantClasses = {
primary: 'btn-primary',
secondary: 'btn-secondary',
danger: 'btn-danger'
};
const sizeClasses = {
small: 'btn-small',
medium: 'btn-medium',
large: 'btn-large'
};
const className = `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]}`;
return (
<button
className={className}
onClick={onClick}
disabled={disabled || loading}
>
{loading ? '加载中...' : children}
</button>
);
}
// 2. 卡片组件
function Card({ title, children, footer }) {
return (
<div className="card">
{title && (
<div className="card-header">
<h3>{title}</h3>
</div>
)}
<div className="card-body">
{children}
</div>
{footer && (
<div className="card-footer">
{footer}
</div>
)}
</div>
);
}
// 3. 模态框组件
function Modal({ isOpen, onClose, title, children }) {
if (!isOpen) return null;
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={e => e.stopPropagation()}>
<div className="modal-header">
<h2>{title}</h2>
<button onClick={onClose} className="modal-close">×</button>
</div>
<div className="modal-body">
{children}
</div>
</div>
</div>
);
}
八、实战练习
// 任务:创建一个简单的任务管理器
function TaskManager() {
const [tasks, setTasks] = useState([
{ id: 1, text: '学习React基础', completed: true },
{ id: 2, text: '练习组件编写', completed: false },
{ id: 3, text: '理解JSX语法', completed: true },
]);
const [newTask, setNewTask] = useState('');
const addTask = () => {
if (!newTask.trim()) return;
const task = {
id: Date.now(), // 简单的时间戳作为ID
text: newTask,
completed: false
};
setTasks([...tasks, task]);
setNewTask('');
};
const toggleTask = (taskId) => {
setTasks(tasks.map(task =>
task.id === taskId
? { ...task, completed: !task.completed }
: task
));
};
const deleteTask = (taskId) => {
setTasks(tasks.filter(task => task.id !== taskId));
};
const completedTasks = tasks.filter(task => task.completed);
const pendingTasks = tasks.filter(task => !task.completed);
return (
<div className="task-manager">
<h1>任务管理器</h1>
{/* 添加新任务 */}
<div className="add-task">
<input
type="text"
value={newTask}
onChange={(e) => setNewTask(e.target.value)}
placeholder="输入新任务..."
onKeyPress={(e) => e.key === 'Enter' && addTask()}
/>
<button onClick={addTask}>添加</button>
</div>
{/* 任务统计 */}
<div className="task-stats">
<p>总计: {tasks.length} | 完成: {completedTasks.length} | 待办: {pendingTasks.length}</p>
</div>
{/* 待办任务 */}
<TaskList
title="待办任务"
tasks={pendingTasks}
onToggle={toggleTask}
onDelete={deleteTask}
/>
{/* 已完成任务 */}
<TaskList
title="已完成任务"
tasks={completedTasks}
onToggle={toggleTask}
onDelete={deleteTask}
showCompleted={true}
/>
</div>
);
}
// 任务列表组件
function TaskList({ title, tasks, onToggle, onDelete, showCompleted = false }) {
if (tasks.length === 0) {
return (
<div className="task-list">
<h3>{title}</h3>
<p className="empty-message">暂无任务</p>
</div>
);
}
return (
<div className="task-list">
<h3>{title} ({tasks.length})</h3>
<ul>
{tasks.map(task => (
<TaskItem
key={task.id}
task={task}
onToggle={onToggle}
onDelete={onDelete}
showCompleted={showCompleted}
/>
))}
</ul>
</div>
);
}
// 任务项组件
function TaskItem({ task, onToggle, onDelete, showCompleted }) {
return (
<li className={`task-item ${task.completed ? 'completed' : ''}`}>
<input
type="checkbox"
checked={task.completed}
onChange={() => onToggle(task.id)}
/>
<span className="task-text">{task.text}</span>
{showCompleted && (
<span className="task-status">✓ 已完成</span>
)}
<button
className="delete-btn"
onClick={() => onDelete(task.id)}
>
删除
</button>
</li>
);
}
关键要点总结
-
JSX是JavaScript的扩展,不是模板语言
-
组件必须返回单个根元素 (或使用Fragment
<>) -
Props是只读的,组件不能修改自己的props
-
key属性在列表中是必需的,用于React识别元素
-
事件处理使用驼峰命名(onClick,不是onclick)
-
条件渲染有多种方式,选择最适合场景的
-
样式可以是内联对象、CSS类或CSS-in-JS
练习建议
-
手写上面的所有例子
-
修改任务管理器,添加:
-
任务优先级(高/中/低)
-
截止日期
-
任务分类
-
-
创建自己的组件库,包括:
-
表单组件(输入框、选择器)
-
布局组件(页头、页脚、侧边栏)
-
数据显示组件(表格、卡片)
-
掌握这些基础后,你就能够构建大部分React应用的基础界面了!