菜鸟教程 -- 学的不仅是技术,更是梦想!

React 教程
(追記) (追記ここまで)

React 组件

React 组件是构建 React 应用的基本单元,可以把组件理解为可复用的、独立的 UI 单元,每个组件封装了自己的结构、样式、逻辑和状态。

React 组件是构建应用的基石,组件可以小到一个按钮,也可以大到整个页面。

组件可以分为:函数组件类组件

从技术角度讲,React 组件就是一个返回 React 元素(通常是 JSX)的 JavaScript 函数或类。

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

将复杂的 UI 拆分成组件树:

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

函数组件

函数组件是定义组件的一种简洁方法。

函数组件是一个接受 props 并返回 React 元素的 JavaScript 函数。

基础语法:

// 方式 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>;

创建一个简单的函数组件:

src/Welcome.js 文件:

import React from 'react';

// 定义一个函数组件
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}

export default Welcome;

在 src/index.js 中渲染该组件:

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"));
// 渲染 Welcome 组件,并传递 name 属性
root.render(<Welcome name="World" />);

这个例子展示了一个接受 name 属性并在页面上显示 "Hello, World!" 的简单组件。


类组件

类组件使用 ES6 类语法定义,通常用于需要管理状态或使用生命周期方法的情况。

基础语法:

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

创建一个类组件:

实例

import React, { Component } from 'react';

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

export default Welcome;

在 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"));
// 渲染 Welcome 组件,并传递 name 属性
root.render(<Welcome name="World" />);

测试实例

接下来我们封装一个输出 "Hello World!" 的组件,组件名为 HelloMessage:

React 实例

functionHelloMessage(props){return <h1>HelloWorld!</h1>; }constelement = <HelloMessage />; constroot = ReactDOM.createRoot(document.getElementById("root")); root.render(element);

尝试一下 »

实例解析:

1、我们可以使用函数定义了一个组件:

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

你也可以使用 ES6 class 来定义一个组件:

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

2、const element = <HelloMessage /> 为用户自定义的组件。

注意,原生 HTML 元素名以小写字母开头,而自定义的 React 类名以大写字母开头,比如 HelloMessage 不能写成 helloMessage。除此之外还需要注意组件类只能包含一个顶层标签,否则也会报错。

如果我们需要向组件传递参数,可以使用 this.props 对象,实例如下:

React 实例

functionHelloMessage(props){return <h1>Hello{props.name}!</h1>; }constelement = <HelloMessagename="Runoob"/>; constroot = ReactDOM.createRoot(document.getElementById("root")); root.render(element);

尝试一下 »

以上实例中 name 属性通过 props.name 来获取。

注意,在添加属性时, class 属性需要写成 className ,for 属性需要写成 htmlFor ,这是因为 class 和 for 是 JavaScript 的保留字。


复合组件

我们可以通过创建多个组件来合成一个组件,即把组件的不同功能点进行分离。

以下实例我们实现了输出网站名字和网址的组件:

React 实例

functionName(props){return <h1>网站名称:{props.name}</h1>; }functionUrl(props){return <h1>网站地址:{props.url}</h1>; }functionNickname(props){return <h1>网站小名:{props.nickname}</h1>; }functionApp(){return( <div> <Namename="菜鸟教程" /> <Urlurl="http://www.runoob.com" /> <Nicknamenickname="Runoob" /> </div> ); }constroot = ReactDOM.createRoot(document.getElementById("root")); root.render( <App /> );

尝试一下 »

实例中 App 组件使用了 Name、Url 和 Nickname 组件来输出对应的信息。


Props(属性)

Props 是组件之间传递数据的方式,类似于函数的参数。

基础用法

// 父组件传递 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 解构

// 推荐:直接解构
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>
 );
}

Props 的类型

Props 可以是任何 JavaScript 值:

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

特殊的 props,用于传递组件的子内容:

// 方式 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>
 );
}

Props 的不可变性

重要原则:永远不要修改 props!

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

组件的组合与复用

组合模式

// 基础组件
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>
 );
}

容器组件模式

// 容器组件:处理逻辑和状态
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>
 );
}

高阶组件思想(通过组合实现)

// 通用的加载状态包装
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>
 );
}

组件命名规范

命名规则

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

文件命名

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

组件的导出与导入

默认导出

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

命名导出

// 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';

混合导出

// 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';

组件设计原则

1. 单一职责原则

每个组件应该只做一件事。

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

2. 保持组件简洁

组件代码不应该超过 200-300 行。

// 好:提取子组件
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

不要传递过多的 props。

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

4. 避免深层嵌套

过深的组件嵌套会导致 props drilling 问题。

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

4 篇笔记 写笔记

  1. #0

    丶小明

    602***[email protected]

    37

    组件名不一定是用单标签,也可以是双标签

    <HelloMessage />

    可以写成如下代码:

    <HelloMessage></HelloMessage>

    XML 的重点有且仅有一个根标签。

    丶小明

    602***[email protected]

    9年前 (2017年09月07日)
  2. #0

    杨钟华

    xdf***[email protected]

    67

    组件名内不能使用 style 样式,例如:假设该组建名为 <HelloMessage />,如果我们写成:<HelloMessage style={{color:'red',textAlign:'center'}}/> 这样,那么该组件名是无 style 样式的,也就是说我们刚写的 style 样式,是无效的,因此我们不能把样式写在该组件中!那么我们应该把样式写在哪里呢? 我们应该把样式写在:

    function HelloMessage(props) {
     return <h1 style={{color:'red',textAlign:'center'}}>Hello World!</h1>;
    }
    

    或者

    var myStyle = {color:'red',textAlign:'center'}
    class HelloMessage extends React.Component {
     render() {
     return <h1 style={myStyle}>Hello World!</h1>;
     }
    }
    
    杨钟华

    杨钟华

    xdf***[email protected]

    8年前 (2018年06月12日)
  3. #0

    ReactDOM.render 是 React 的最基本方法用于将模板转为 HTML 语言,并插入指定的 DOM 节点。

    ReactDOM.render(template,targetDOM) 方法接收两个参数:

    • 第一个是创建的模板,多个 dom 元素外层需使用一个标签进行包裹,如 <div>;
    • 第二个参数是插入该模板的目标位置。

    若要为创建的某个元素增加 class 属性,不能直接定义 class 而要用 className,因为 class 是 javascript 中的保留字。例如给 input 添加 className 并更改样式:

    <input type="text" className="userName" value={value}/> 
    .userName{background: yellow} // 在CSS样式中定义

    同样可以定义行内样式,将所有的样式包裹在一个对象中,以类似变量的形式给 style 属性赋值,注意样式属性要用驼峰命名法表示,如: backgroundColor 而不是 background-color,fontSize 而不是 font-size:

    <input type="text" style={{"backgroundColor":"yellow","color":"red"}} value={value}/>

    另外可以直接将样式赋值给一个变量,把变量赋值给 style 属性,如下:

    <div id="container"></div>
    <script type="text/babel">
    let value = "demo1";
    let buttonName = "submit";
    let inputStyle = {
     "backgroundColor":"yellow",
     "color":"red"
    };
    ReactDOM.render(
     <div>
     <input type="text" style={inputStyle} value={value}/> 
     <button>{buttonName}</button>
     </div>,
     document.getElementById("container")
    )
    </script>
    hr 8年前 (2018年06月22日)
  4. #0

    做自己的小太阳

    251***[email protected]

    36

    对创建多个组件的代码,做了点小修改,帮助大家理解。

    <WebSite name="菜鸟教程" site=" http://www.runoob.com" />,这种形式传入的 name 和 url 值,只能在 WebSit 组件中用 this.props.xxx 来使用。虽然原来的代码中,Name 和 Site 组件中也是以同样的形式使用的,但并不是因为这条语句的作用,而是因为 <Name name={this.props.name} /> <Link site={this.props.site} /> 。所以我特意将这几行代码做了修改,方便大家感受感受!

    WebSite 组件中:

    <Name title={this.props.name}/> 
    // 将this.props.name以title名称传给Name组件,Name通过this.props.title来使用其值
    <Url site={this.props.url}/> 
    // 将this.props.url以site名称传给Name组件,Name通过this.props.site来使用其值

    Name 组件中:

    <h1>{this.props.title}</h1>

    Site 组件中:

    <a href={this.props.site} rel="nofollow">{this.props.site}</a>

    做自己的小太阳

    251***[email protected]

    8年前 (2018年07月12日)

点我分享笔记

  • 昵称 (必填)
  • 邮箱 (必填)
  • 引用地址

AltStyle によって変換されたページ (->オリジナル) /