React基础:语法、组件与JSX

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>
  );
}

关键要点总结

  1. JSX是JavaScript的扩展,不是模板语言

  2. 组件必须返回单个根元素 (或使用Fragment <>

  3. Props是只读的,组件不能修改自己的props

  4. key属性在列表中是必需的,用于React识别元素

  5. 事件处理使用驼峰命名(onClick,不是onclick)

  6. 条件渲染有多种方式,选择最适合场景的

  7. 样式可以是内联对象、CSS类或CSS-in-JS

练习建议

  1. 手写上面的所有例子

  2. 修改任务管理器,添加:

    • 任务优先级(高/中/低)

    • 截止日期

    • 任务分类

  3. 创建自己的组件库,包括:

    • 表单组件(输入框、选择器)

    • 布局组件(页头、页脚、侧边栏)

    • 数据显示组件(表格、卡片)

掌握这些基础后,你就能够构建大部分React应用的基础界面了!

相关推荐
宁雨桥2 小时前
Vue项目中iframe嵌入页面实现免登录的完整指南
前端·javascript·vue.js
css趣多多2 小时前
Elment UI 布局组件
javascript
无法长大2 小时前
Mac M1 环境下使用 Rust Tauri 将 Vue3 项目打包成 APK 完整指南
android·前端·macos·rust·vue3·tauri·打包apk
LongJ_Sir2 小时前
Cesium--可拖拽气泡弹窗(对话框尾巴,Vue3版)
前端·javascript·vue.js
im_AMBER2 小时前
消失的最后一秒:SSE 流式联调中的“时序竞争”
前端·笔记·学习·http·sse
GDAL2 小时前
Electron IPC 通信深入全面讲解教程
javascript·electron
摘星编程2 小时前
React Native + OpenHarmony:removeClippedSubviews性能优化
react native·react.js·性能优化
RFCEO2 小时前
前端编程 课程十、:CSS 系统学习学前知识/准备
前端·css·层叠样式表·动效设计·前端页面布局6大通用法则·黄金分割比例法则·设计美观的前端
雄狮少年2 小时前
AI Agent Workflow基类及实现类,快速实现一个react agent,可直接运行
人工智能·windows·react.js