当前位置: 首页 > news >正文

组件化思想

下面,我们来系统的梳理关于 React 组件化思想 的基本知识点:


一、组件化基础概念

1.1 什么是组件化?

组件化是将UI拆分为独立、可复用代码单元的开发范式。在React中,组件是构建用户界面的基本单位,每个组件封装了:

  • 结构(JSX)
  • 样式(CSS)
  • 行为(JavaScript)
  • 状态(State)
  • 交互逻辑

1.2 为什么需要组件化?

优势说明
复用性一次开发,多处使用
可维护性独立更新不影响其他部分
分而治之复杂问题拆解为小问题
团队协作并行开发不同组件
可测试性独立单元易于测试

1.3 React组件类型

类型特点适用场景
函数组件无状态、简洁展示型组件
类组件有生命周期、状态复杂交互组件(React 16.8前主流)
Hooks组件函数组件+状态能力现代React开发首选

二、组件设计原则

2.1 单一职责原则

一个组件只做一件事:

// 反例:混合了展示和逻辑
function UserListWithActions() {// ... 数据获取、渲染列表、操作处理
}// 正例:拆分
function UserList({ users }) {// 只负责渲染
}function UserContainer() {const [users, setUsers] = useState([]);// 负责数据获取return <UserList users={users} />
}

2.2 封装与隔离

组件应隐藏内部实现细节,只暴露必要接口:

// 计数器组件
function Counter() {const [count, setCount] = useState(0);// 内部实现细节,外部无需知道const increment = () => setCount(c => c + 1);return (<div><button onClick={increment}>+</button><span>{count}</span></div>);
}

2.3 组合优于继承

React推荐使用组合而非继承构建复杂UI:

// 使用组合的弹窗组件
function Dialog({ title, children }) {return (<div className="dialog"><h2>{title}</h2><div className="content">{children}  {/* 内容由外部传入 */}</div></div>);
}// 使用
<Dialog title="警告"><p>确定要删除吗?</p><div className="actions"><button>取消</button><button>确认</button></div>
</Dialog>

三、组件通信模式

3.1 父传子:Props

function Parent() {const data = "Hello from parent";return <Child message={data} />;
}function Child({ message }) {return <p>{message}</p>;
}

3.2 子传父:回调函数

function Parent() {const handleChildEvent = (data) => {console.log("来自子组件的数据:", data);};return <Child onEvent={handleChildEvent} />;
}function Child({ onEvent }) {return (<button onClick={() => onEvent(Math.random())}>发送数据</button>);
}

3.3 兄弟组件通信

通过状态提升到共同父组件:

function Parent() {const [sharedState, setSharedState] = useState(null);return (<><SiblingA state={sharedState} setState={setSharedState} /><SiblingB state={sharedState} setState={setSharedState} /></>);
}

3.4 深层嵌套组件通信

使用Context API:

const ThemeContext = createContext('light');function App() {return (<ThemeContext.Provider value="dark"><DeepNestedComponent /></ThemeContext.Provider>);
}function DeepNestedComponent() {const theme = useContext(ThemeContext);return <div>当前主题: {theme}</div>;
}

四、组件生命周期(类组件)

4.1 生命周期图谱

挂载阶段
constructor
render
componentDidMount
更新阶段
shouldComponentUpdate
render
componentDidUpdate
卸载阶段
componentWillUnmount

4.2 关键生命周期方法

  • constructor:初始化state,绑定方法
  • componentDidMount:DOM操作、数据请求
  • shouldComponentUpdate:性能优化关键
  • componentDidUpdate:更新后DOM操作
  • componentWillUnmount:清理定时器/订阅

五、函数组件与Hooks

5.1 函数组件优势

  • 代码更简洁
  • 无this绑定问题
  • 易于测试
  • 更好的类型推断

5.2 核心Hooks

Hook作用等效生命周期
useState状态管理this.setState
useEffect副作用处理componentDidMount + componentDidUpdate + componentWillUnmount
useContext访问Contextstatic contextType
useRef引用DOM/保存可变值createRef
useMemo记忆计算结果shouldComponentUpdate
useCallback记忆函数方法绑定优化

5.3 自定义Hook

封装可复用逻辑:

function useWindowSize() {const [size, setSize] = useState({width: window.innerWidth,height: window.innerHeight});useEffect(() => {const handleResize = () => setSize({width: window.innerWidth,height: window.innerHeight});window.addEventListener('resize', handleResize);return () => window.removeEventListener('resize', handleResize);}, []);return size;
}// 使用
function MyComponent() {const { width } = useWindowSize();return <p>窗口宽度: {width}px</p>;
}

六、组件设计模式

6.1 容器组件与展示组件

容器组件展示组件
职责数据获取、业务逻辑UI呈现
复用性
状态通常有状态通常无状态
示例用户数据容器用户卡片

6.2 高阶组件(HOC)

接收组件,返回增强组件:

function withLogger(WrappedComponent) {return function(props) {useEffect(() => {console.log(`组件 ${WrappedComponent.name} 已渲染`);}, []);return <WrappedComponent {...props} />;};
}const EnhancedComponent = withLogger(MyComponent);

6.3 渲染属性(Render Props)

通过函数prop共享代码:

class MouseTracker extends React.Component {state = { x: 0, y: 0 };handleMouseMove = (e) => {this.setState({ x: e.clientX, y: e.clientY });};render() {return (<div onMouseMove={this.handleMouseMove}>{this.props.render(this.state)}</div>);}
}// 使用
<MouseTracker render={({ x, y }) => (<p>鼠标位置: {x}, {y}</p>
)} />

七、组件性能优化

7.1 避免不必要的渲染

  • React.memo:记忆函数组件
const MemoComponent = React.memo(MyComponent);
  • PureComponent:类组件浅比较
class PureComp extends React.PureComponent {}

7.2 正确使用key

// 列表项使用稳定唯一key
{items.map(item => (<ListItem key={item.id} item={item} />
))}

7.3 懒加载组件

const LazyComponent = React.lazy(() => import('./HeavyComponent'));function App() {return (<Suspense fallback={<Spinner />}><LazyComponent /></Suspense>);
}

八、组件测试策略

8.1 测试金字塔

70%20%10%测试类型分布单元测试集成测试端到端测试

8.2 测试工具

  • Jest:测试框架
  • React Testing Library:组件测试
  • Cypress:端到端测试

8.3 组件测试示例

import { render, screen, fireEvent } from '@testing-library/react';test('按钮点击后显示文本', () => {render(<Button />);fireEvent.click(screen.getByText('点击'));expect(screen.getByText('已点击')).toBeInTheDocument();
});

九、组件化最佳实践

  1. 命名规范:组件使用PascalCase,props使用camelCase
  2. 文件结构:一个组件一个文件夹,包含组件、样式、测试
components/Button/Button.jsxButton.module.cssButton.test.jsindex.js
  1. PropTypes:定义props类型(TypeScript更优)
Button.propTypes = {variant: PropTypes.oneOf(['primary', 'secondary']),onClick: PropTypes.func.isRequired
};
  1. 文档驱动开发:使用Storybook组件目录

十、组件设计实战

10.1 设计可配置按钮

function Button({children,variant = 'primary',size = 'medium',disabled = false,onClick
}) {const classNames = `btn btn-${variant} btn-${size} ${disabled ? 'disabled' : ''}`;return (<button className={classNames} disabled={disabled}onClick={onClick}>{children}</button>);
}

10.2 构建表单组件体系

function Form({ children, onSubmit }) {return <form onSubmit={onSubmit}>{children}</form>;
}function FormItem({ label, children, error }) {return (<div className="form-item"><label>{label}</label>{children}{error && <div className="error">{error}</div>}</div>);
}function Input({ ...props }) {return <input className="form-input" {...props} />;
}// 使用
<Form onSubmit={handleSubmit}><FormItem label="用户名" error={errors.username}><Input value={username} onChange={e => setUsername(e.target.value)}/></FormItem>
</Form>

总结

  • 组件是React应用的构建块,遵循单一职责原则
  • 通过Props、Context、自定义事件实现组件通信
  • 函数组件+Hooks是现代化React开发首选
  • 使用组合模式构建复杂UI
  • 通过React.memo、正确使用key等优化性能
  • 建立组件文档和测试保障质量
http://www.dtcms.com/a/279949.html

相关文章:

  • Brooks 低温泵On-Board Cryopump 安装和维护手法Installation and Maintenance Manual
  • aspnetcore Mvc配置选项中的ModelBindingMessageProvider
  • 第二章 基于新版Onenet搭建云服务(stm32物联网)
  • PyTorch中torch.topk()详解:快速获取最大值索引
  • @Resource 注解的空值处理(默认行为与容器实现)
  • 冲刺阶段项目进度压力大,如何组织高效冲刺
  • 大屏搭建多个图表不自适应问题
  • H264编码结构和解析
  • 第四章 uniapp实现兼容多端的树状族谱关系图,剩余组件
  • ESP32 OTA升级详解:使用Arduino OTA库实现无线固件更新
  • HTML 文本格式化标签
  • java--ThreadLocal创建以及get源码解析
  • http常见状态码
  • 苦练Python第18天:Python异常处理锦囊
  • 【论文阅读】Masked Autoencoders Are Effective Tokenizers for Diffusion Models
  • rsyslog简单应用
  • STM32F769I-DISCO 串口调试
  • Linux上基于C/C++头文件查找对应的依赖开发库
  • SAP B1认证资料-题目
  • 分布式系统中实现临时节点授权的高可用性与一致性
  • 哈希扩展 --- 海量数据处理
  • CISSP知识点汇总- 通信与网络安全
  • 15.Python 列表元素的偏移
  • Java学习————————ThreadLocal
  • python Gui界面小白入门学习二
  • python高阶调试技巧,替代print
  • 14.推荐使用 dict.get(key) 而不是 dict[key]
  • redis配置(Xshell连接centos7的基础上)
  • Modbus 开发工具实战:ModScan32 与 Wireshark 抓包分析(一
  • Python `WeakValueDictionary` 用法详解