加载笔记内容...
加载笔记内容...
优点
缺陷
HOC 是一个接收一个组件并返回一个新组件的函数。它允许你在不修改其代码的情况下为组件添加额外的功能。HOC 通常用于下列场景:
React Hooks 是从 React 16.8 开始引入的一个新特性,允许你在不使用 class 的情况下使用 state 和其他 React 特性。Hooks 用于以下场景:
componentDidMount
, componentDidUpdate
)来处理的。但现在,可以使用 useEffect
Hook 来达到相同的效果。useState
和 useReducer
,你可以在函数组件中方便地管理状态。总之,选择 HOC 还是 Hooks 取决于你的具体需求和现有的代码库。但随着 React 社区逐渐向 Hooks 迁移,建议新的开发或重构时首先考虑使用 Hooks。
React Hooks 是 React 16.8 之后引入的一个新特性,它允许你在不写 class 组件的情况下使用 state 和其他 React 的功能。在引入 Hooks 之前,React 社区常常使用高阶组件 (Higher-Order Components,简称 HOC) 和 render props 来复用组件逻辑。而 Hooks 提供了一个更加简洁和直观的方式来复用和管理组件逻辑。
所以,可以说 React Hooks 在许多情况下都可以替代 HOC。但这并不意味着 Hooks 完全取代了 HOC。以下是 Hooks 和 HOC 在一些方面的比较:
尽管 Hooks 在很多情况下提供了更加简洁和直观的方法来复用和管理组件逻辑,但 HOC 在某些特定情况下仍然有它的价值。例如,与某些第三方库的集成可能仍然需要使用 HOC。
总的来说,虽然 Hooks 在许多常见的用例中可以替代 HOC,但根据你的具体需求和场景,选择最合适的方法仍然很重要。
高阶组件 (Higher-Order Components, HOC) 是 React 中用于复用组件逻辑的一种模式。一个高阶组件接受一个组件并返回一个新组件。以下是一些经典的 HOC 例子:
1function withLoading(Component) {
2 return function EnhancedComponent({ isLoading, ...props }) {
3 if (isLoading) {
4 return <div>Loading...</div>;
5 }
6 return <Component {...props} />;
7 };
8}
使用:
1const ListWithLoading = withLoading(List);
2<ListWithLoading isLoading={dataLoading} data={data} />
1class ErrorBoundary extends React.Component {
2 state = { hasError: false };
3
4 static getDerivedStateFromError(error) {
5 return { hasError: true };
6 }
7
8 componentDidCatch(error, info) {
9 logErrorToService(error, info);
10 }
11
12 render() {
13 if (this.state.hasError) {
14 return <div>Something went wrong!</div>;
15 }
16 return this.props.children;
17 }
18}
19
20function withErrorBoundary(Component) {
21 return props => (
22 <ErrorBoundary>
23 <Component {...props} />
24 </ErrorBoundary>
25 );
26}
使用:
1const SafeComponent = withErrorBoundary(MyComponent);
1function withUser(Component) {
2 return function EnhancedComponent(props) {
3 const user = getCurrentUser();
4 return <Component {...props} user={user} />;
5 };
6}
使用:
1const UserAwareComponent = withUser(SomeComponent);
react-router-dom
的 HOC,为你的组件提供路由属性(如 history
, location
和 match
)。1import { withRouter } from 'react-router-dom';
2
3function ComponentNeedingRouterProps({ history, location, match }) {
4 // 使用 history, location, match 作一些操作
5}
6
7export default withRouter(ComponentNeedingRouterProps);
react-redux
的 HOC,用于将 Redux store 与 React 组件连接起来。1import { connect } from 'react-redux';
2
3function mapStateToProps(state) {
4 return {
5 items: state.items,
6 };
7}
8
9function MyComponent({ items }) {
10 // 使用来自 Redux store 的 items
11}
12
13export default connect(mapStateToProps)(MyComponent);
这些只是一些常见和经典的 HOC 例子。实际上,你可以根据应用的需求创建各种复杂的 HOC,以达到代码复用和逻辑抽象的目的。
自定义 Hooks 是封装和复用组件逻辑的一种方法,特别是当你发现自己在多个组件中重复使用相同的逻辑时。自定义 Hooks 允许你提取这些重复的逻辑到单独的函数中,这样其他组件可以复用它而不需要重复代码。
缘由: 如果你的应用中有多个组件都需要从某个 API 获取数据,你可能会发现自己重复编写相同的状态管理和数据提取逻辑。
自定义 Hook:
1import { useState, useEffect } from 'react';
2
3function useFetch(url) {
4 const [data, setData] = useState(null);
5 const [loading, setLoading] = useState(true);
6 const [error, setError] = useState(null);
7
8 useEffect(() => {
9 fetch(url)
10 .then(response => {
11 if (!response.ok) throw new Error("Network response was not ok");
12 return response.json();
13 })
14 .then(data => {
15 setData(data);
16 setLoading(false);
17 })
18 .catch(error => {
19 setError(error);
20 setLoading(false);
21 });
22 }, [url]);
23
24 return { data, loading, error };
25}
使用:
1function Component() {
2 const { data, loading, error } = useFetch('https://api.example.com/data');
3
4 if (loading) return <div>Loading...</div>;
5 if (error) return <div>Error: {error.message}</div>;
6
7 return <div>{data && data.map(item => <div key={item.id}>{item.name}</div>)}</div>;
8}
缘由: 在响应式设计中,你可能需要根据窗口大小来更改组件的行为或样式。你可能会在多个地方需要这种逻辑。
自定义 Hook:
1import { useState, useEffect } from 'react';
2
3function useWindowSize() {
4 const [size, setSize] = useState({ width: window.innerWidth, height: window.innerHeight });
5
6 useEffect(() => {
7 const handleResize = () => {
8 setSize({
9 width: window.innerWidth,
10 height: window.innerHeight
11 });
12 };
13
14 window.addEventListener('resize', handleResize);
15 return () => {
16 window.removeEventListener('resize', handleResize);
17 };
18 }, []);
19
20 return size;
21}
使用:
1function Component() {
2 const { width, height } = useWindowSize();
3
4 return <div>Window size is {width}x{height}</div>;
5}
封装自定义 Hooks 的主要原因是为了复用和抽象组件逻辑,使组件更加清晰、可维护并减少代码冗余。当你在不同的组件或应用中反复使用相同的逻辑时,建议考虑创建一个自定义 Hook。
order
属性是 Flexbox(弹性盒子)布局中的一个重要属性,用于控制 flex 容器中项目的显示顺序。默认情况下,项目在 flex 容器中的排列顺序与其在源代码中的顺序相同。通过给项目分配一个 order
值,你可以控制项目的显示顺序,而不必改变源代码中的顺序。
属性详解:
order
当你设置了项目的 order
属性后,较小的数字会先显示,较大的数字稍后显示。如果多个项目有相同的 order
值,它们之间的顺序将与它们在源代码中的顺序相同。
示例:
假设你有以下 HTML 结构:
1<div class="flex-container">
2 <div class="flex-item">1</div>
3 <div class="flex-item">2</div>
4 <div class="flex-item">3</div>
5</div>
以及以下 CSS:
1.flex-container {
2 display: flex;
3}
4
5.flex-item:nth-child(1) {
6 order: 2;
7}
8
9.flex-item:nth-child(2) {
10 order: 1;
11}
12
13.flex-item:nth-child(3) {
14 order: 3;
15}
在上述例子中,尽管源代码中的顺序是 1, 2, 3,但由于我们设置的 order
属性,显示顺序会是 2, 1, 3。
在实际应用中,order
属性很有用,因为它允许你在不修改 HTML 源代码的情况下重新排序内容,这在响应式设计中特别有用,因为你可以为不同的屏幕尺寸指定不同的内容顺序。
创建一个简单的 Schedule
类,用于控制并发的 Promise
,通常涉及到以下几个步骤:
下面是一个基于上述思路的 Schedule
类的实现:
1class Schedule {
2 constructor(concurrency) {
3 this.concurrency = concurrency; // 最大并发数量
4 this.waiting = []; // 等待执行的任务队列
5 this.running = []; // 正在执行的任务队列
6 }
7
8 // 执行任务
9 execute() {
10 while (this.running.length < this.concurrency && this.waiting.length) {
11 const task = this.waiting.shift(); // 从等待队列中取出任务
12 this.running.push(task);
13
14 task()
15 .then(() => {
16 this._complete(task); // 成功完成后,将任务从正在执行队列中移除
17 })
18 .catch(() => {
19 this._complete(task); // 出错后,将任务从正在执行队列中移除
20 });
21 }
22 }
23
24 // 添加任务
25 add(task) {
26 this.waiting.push(task);
27 this.execute();
28 }
29
30 // 完成任务
31 _complete(task) {
32 const index = this.running.indexOf(task);
33 if (index > -1) {
34 this.running.splice(index, 1); // 从正在执行队列中移除已完成的任务
35 }
36 this.execute(); // 检查是否有新的任务可以开始执行
37 }
38}
39
40// 使用示例
41const scheduler = new Schedule(2); // 最大并发为2
42
43// 模拟异步任务
44function taskGenerator(name, delay) {
45 return () => {
46 console.log(`Task ${name} started`);
47 return new Promise((resolve) => {
48 setTimeout(() => {
49 console.log(`Task ${name} completed`);
50 resolve();
51 }, delay);
52 });
53 };
54}
55
56scheduler.add(taskGenerator('A', 1000));
57scheduler.add(taskGenerator('B', 500));
58scheduler.add(taskGenerator('C', 1200));
59scheduler.add(taskGenerator('D', 700));
上面的代码首先定义了一个 Schedule
类,用于并发控制,然后提供了一个模拟的异步任务生成器 taskGenerator
。最后,我们为 scheduler
添加了四个任务,由于我们设置的最大并发为2,所以会看到首先开始执行任务A和B,然后执行任务C和D。