React-Komponenten

React-Komponenten sind die grundlegenden Bausteine von React-Anwendungen. Eine Komponente kann als wiederverwendbare, eigenständige UI-Einheit verstanden werden. Jede Komponente kapselt ihre eigene Struktur, Stile, Logik und ihren eigenen Zustand.

React-Komponenten sind der Eckpfeiler beim Erstellen von Anwendungen. Eine Komponente kann so klein wie ein Button oder so groß wie eine ganze Seite sein.

Komponenten können unterteilt werden in:FunktionskomponentenundKlassenkomponenten。

Technisch gesehen ist eine React-Komponente eine JavaScript-Funktion oder -Klasse, die ein React-Element (üblicherweise JSX) zurückgibt.

// 最简单的组件
function Hello() {
  return <h1>Hello, World!</h1>;
}

Zerlegen Sie komplexe UI in einen Komponentenbaum:

App
├── Header
│   ├── Logo
│   └── Navigation
│       ├── NavItem
│       └── NavItem
├── Main
│   ├── Sidebar
│   └── Content
│       ├── Article
│       └── Article
└── Footer

Funktionskomponenten

Funktionskomponenten sind eine prägnante Möglichkeit, Komponenten zu definieren.

Eine Funktionskomponente ist eine JavaScript-Funktion, die Props akzeptiert und ein React-Element zurückgibt.

Grundlegende Syntax:

// 方式 1:函数声明
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// 方式 2:箭头函数
const Welcome = (props) => {
  return <h1>Hello, {props.name}</h1>;
};

// 方式 3:简化写法(单行返回)
const Welcome = (props) => <h1>Hello, {props.name}</h1>;

Erstellen Sie eine einfache Funktionskomponente:

Datei src/Welcome.js:

import React from 'react';

// Eine Funktionskomponente definieren
function Welcome(props) {
  return <h1>Hello, {props.name}!</h1>;
}

export default Welcome;

Rendern Sie die Komponente in src/index.js:

Datei src/index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Welcome from './Welcome';

const root = ReactDOM.createRoot(document.getElementById("root"));
// Die Welcome-Komponente rendern und die name-Prop übergeben
root.render(<Welcome name="World" />);

Dieses Beispiel zeigt eine einfache Komponente, die eine name-Prop akzeptiert und "Hello, World!" auf der Seite anzeigt.


Klassenkomponenten

Klassenkomponenten werden mit der ES6-Klassensyntax definiert und typischerweise verwendet, wenn Sie State verwalten oder Lifecycle-Methoden verwenden müssen.

Grundlegende Syntax:

import React, { Component } from 'react';
class Welcome extends Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

Erstellen Sie eine Klassenkomponente:

Beispiel

import React, { Component } from 'react';

class Welcome extends Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

export default Welcome;

Rendern Sie die Komponente in src/index.js:

Beispiel

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Welcome from './Welcome';

const root = ReactDOM.createRoot(document.getElementById("root"));
// Die Welcome-Komponente rendern und die name-Prop übergeben
root.render(<Welcome name="World" />);

Testbeispiel

Als Nächstes erstellen wir eine Komponente, die "Hello World!" ausgibt, genannt HelloMessage:

React-Beispiel

function HelloMessage(props) { return <h1>Hello World!</h1>; } const element = <HelloMessage />; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( element );

Ausprobieren »

Beispielanalyse:

1. Wir können eine Komponente mit einer Funktion definieren:

function HelloMessage(props) {
    return <h1>Hello World!</h1>;
}

Man kann auch eine ES6-Klasse verwenden, um eine Komponente zu definieren:

class Welcome extends React.Component {
  render() {
    return <h1>Hello World!</h1>;
  }
}

2, const element = <HelloMessage />ist eine benutzerdefinierte Komponente.

Beachten Sie, dass native HTML-Elementnamen mit Kleinbuchstaben beginnen, während benutzerdefinierte React-Klassennamen mit Großbuchstaben beginnen. Zum Beispiel kann HelloMessage nicht als helloMessage geschrieben werden. Außerdem kann eine Komponentenklasse nur ein Tag der obersten Ebene enthalten; andernfalls wird ein Fehler gemeldet.

Wenn wir Parameter an eine Komponente übergeben müssen, können wir das Objektthis.propsverwenden, Beispiel wie folgt:

React-Beispiel

function HelloMessage(props) { return <h1>Hello {props.name}!</h1>; } const element = <HelloMessage name="Example"/>; const root = ReactDOM.createRoot(document.getElementById("root")); root.render( element );

Ausprobieren »

Im obigen Beispiel wird die Propnamedurchprops.nameerhalten.

Hinweis: Beim Hinzufügen von Attributen muss das class-Attribut als className geschrieben werden und das for-Attribut als htmlFor. Das liegt daran, dass class und for reservierte Wörter in JavaScript sind.


Zusammengesetzte Komponenten

Wir können mehrere Komponenten kombinieren, um eine Komponente zu erstellen, das heißt, die verschiedenen funktionalen Aspekte einer Komponente zu trennen.

Das folgende Beispiel implementiert eine Komponente, die den Website-Namen und die URL ausgibt:

React-Beispiel

function Name(props) { return <h1>Website-Name:{props.name}</h1>; } function Url(props) { return <h1>Website-Adresse:{props.url}</h1>; } function Nickname(props) { return <h1>Website-Nickname:{props.nickname}</h1>; } function App() { return ( <div> <Name name="Example" /> <Url url="http://www.example.com" /> <Nickname nickname="Example" /> </div> ); } const root = ReactDOM.createRoot(document.getElementById("root")); root.render( <App /> );

Ausprobieren »

Im Beispiel verwendet die App-Komponente die Komponenten Name, Url und Nickname, um die entsprechenden Informationen auszugeben.


Props (Eigenschaften)

Props sind eine Möglichkeit, Daten zwischen Komponenten zu übergeben, ähnlich wie Funktionsparameter.

Grundlegende Verwendung

// 父组件传递 props
function App() {
  return (
    <div>
      <Greeting name="Alice" age={25} />
      <Greeting name="Bob" age={30} />
    </div>
  );
}
// 子组件接收 props
function Greeting(props) {
  return (
    <div>
      <h1>Hello, {props.name}!</h1>
      <p>Age: {props.age}</p>
    </div>
  );
}

Props-Destrukturierung

// 推荐:直接解构
function Greeting({ name, age }) {
  return (
    <div>
      <h1>Hello, {name}!</h1>
      <p>Age: {age}</p>
    </div>
  );
}
// 带默认值的解构
function Button({ text = "Submit", variant = "primary", disabled = false }) {
  return (
    <button className={variant} disabled={disabled}>
      {text}
    </button>
  );
}

Typen von Props

Props können beliebige JavaScript-Werte sein:

function Demo() {
  const user = { name: "Alice", age: 25 };
  const numbers = [1, 2, 3, 4, 5];
  const handleClick = () => alert("Clicked!");
  return (
    <MyComponent
      // 字符串
      title="Hello"
      // 数字
      count={42}
      // 布尔值
      isActive={true}
      // 数组
      items={numbers}
      // 对象
      user={user}
      // 函数
      onClick={handleClick}
      // JSX
      children={<p>This is content</p>}
    />
  );
}

Children-Props

Spezielle Props, die verwendet werden, um den Kindinhalt einer Komponente zu übergeben:

// 方式 1:使用 props.children
function Card(props) {
  return (
    <div className="card">
      <div className="card-body">
        {props.children}
      </div>
    </div>
  );
}
// 方式 2:解构 children
function Card({ children, title }) {
  return (
    <div className="card">
      {title && <h2>{title}</h2>}
      <div className="card-body">{children}</div>
    </div>
  );
}
// 使用
function App() {
  return (
    <Card title="My Card">
      <p>This is the card content</p>
      <button>Click me</button>
    </Card>
  );
}

Unveränderlichkeit von Props

Wichtiges Prinzip: Props niemals ändern!

// 错误:修改 props
function BadComponent(props) {
  props.name = "Changed"; // 绝对不要这样做!
  return <h1>{props.name}</h1>;
}
// 正确:将 props 视为只读
function GoodComponent({ name }) {
  const displayName = name.toUpperCase(); // 创建新值
  return <h1>{displayName}</h1>;
}

Komponentenkomposition und Wiederverwendung

Kompositionsmuster

// 基础组件
function Avatar({ src, alt }) {
  return <img src={src} alt={alt} className="avatar" />;
}
function UserInfo({ name, email }) {
  return (
    <div>
      <h3>{name}</h3>
      <p>{email}</p>
    </div>
  );
}
// 组合成复杂组件
function UserCard({ user }) {
  return (
    <div className="user-card">
      <Avatar src={user.avatar} alt={user.name} />
      <UserInfo name={user.name} email={user.email} />
    </div>
  );
}

Container-Komponenten-Muster

// 容器组件:处理逻辑和状态
function Panel({ title, children, collapsible = false }) {
  const [isOpen, setIsOpen] = useState(true);
  return (
    <div className="panel">
      <div className="panel-header">
        <h2>{title}</h2>
        {collapsible && (
          <button onClick={() => setIsOpen(!isOpen)}>
            {isOpen ? "Collapse" : "Expand"}
          </button>
        )}
      </div>
      {isOpen && (
        <div className="panel-content">
          {children}
        </div>
      )}
    </div>
  );
}
// 使用
function App() {
  return (
    <Panel title="Settings" collapsible>
      <p>Your settings here...</p>
    </Panel>
  );
}

Konzept der Higher-Order-Komponente (durch Komposition implementiert)

// 通用的加载状态包装
function WithLoading({ isLoading, children }) {
  if (isLoading) {
    return <div>Loading...</div>;
  }
  return children;
}
// 使用
function UserList({ users, isLoading }) {
  return (
    <WithLoading isLoading={isLoading}>
      <ul>
        {users.map(user => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </WithLoading>
  );
}

Namenskonventionen für Komponenten

Namensregeln

// 正确:大写字母开头(PascalCase)
function UserProfile() { }
function BlogPost() { }
function NavBar() { }
// 错误:小写字母开头
function userProfile() { } // React 会将其视为 HTML 标签

Dateibenennung

// 推荐的文件结构
src/
├── components/
│   ├── Button.jsx          // oder  Button.js
│   ├── UserCard.jsx
│   ├── Navigation/
│   │   ├── Navigation.jsx
│   │   ├── NavItem.jsx
│   │   └── index.js        // 导出 Navigation

Exportieren und Importieren von Komponenten

Standardexport

// Button.jsx
export default function Button({ text }) {
  return <button>{text}</button>;
}
// App.jsx
import Button from './Button';

Benannter Export

// components.jsx
export function Button({ text }) {
  return <button>{text}</button>;
}
export function Input({ value, onChange }) {
  return <input value={value} onChange={onChange} />;
}
// App.jsx
import { Button, Input } from './components';

Gemischter Export

// Card.jsx
export default function Card({ children }) {
  return <div className="card">{children}</div>;
}
export function CardHeader({ title }) {
  return <div className="card-header">{title}</div>;
}
export function CardBody({ children }) {
  return <div className="card-body">{children}</div>;
}
// App.jsx
import Card, { CardHeader, CardBody } from './Card';

Prinzipien für das Komponentendesign

1. Single-Responsibility-Prinzip

Jede Komponente sollte eine Sache tun.

// 不好:组件做太多事情
function UserDashboard() {
  // 获取用户数据
  // 处理表单
  // 显示图表
  // 处理导航
  // ...
}
// 好:拆分成多个组件
function UserDashboard() {
  return (
    <div>
      <UserProfile />
      <UserStats />
      <UserActivity />
    </div>
  );
}

2. Komponenten einfach halten

Der Komponentencode sollte 200-300 Zeilen nicht überschreiten.

// 好:提取子组件
function ProductCard({ product }) {
  return (
    <div className="product-card">
      <ProductImage src={product.image} />
      <ProductInfo name={product.name} price={product.price} />
      <ProductActions productId={product.id} />
    </div>
  );
}

3. Props sinnvoll einsetzen

Nicht zu viele Props übergeben.

// 不好:props 过多
function User({ name, age, email, address, phone, company, role, ... }) { }
// 好:使用对象
function User({ user }) {
  const { name, age, email } = user;
  // ...
}

4. Tiefe Verschachtelung vermeiden

Übermäßig tiefe Komponentenverschachtelung kann das Props-Drilling-Problem verursachen.

// 问题:props 需要层层传递
<App>
  <Layout user={user}>
    <Sidebar user={user}>
      <Menu user={user}>
        <MenuItem user={user} />
      </Menu>
    </Sidebar>
  </Layout>
</App>
// 解决:使用 Context 或状态管理
Andere Erweiterungen