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

React底层常见的设计模式

在React中,常见的设计模式为开发者提供了结构化和可重用的解决方案,有助于提高代码的可维护性和可扩展性。以下是对React中几种常见设计模式的详细解析,并附上示例代码和注释:

1. 容器组件与展示组件模式(Container/Presentational Pattern)

描述
容器组件负责数据获取、状态管理和业务逻辑,而展示组件仅负责渲染UI,不直接管理状态。

示例代码

// 展示组件:TodoItem.js
import React from 'react';

const TodoItem = ({ todo }) => (
  <div>
    <span>{todo.text}</span>
    <button onClick={() => alert(`Completed ${todo.text}`)}>Complete</button>
  </div>
);

export default TodoItem;

// 容器组件:TodoList.js
import React, { Component } from 'react';
import TodoItem from './TodoItem';

class TodoList extends Component {
  state = {
    todos: [
      { id: 1, text: 'Learn React' },
      { id: 2, text: 'Learn Redux' },
    ],
  };

  render() {
    return (
      <div>
        <h1>Todo List</h1>
        <ul>
          {this.state.todos.map(todo => (
            <li key={todo.id}>
              <TodoItem todo={todo} />
            </li>
          ))}
        </ul>
      </div>
    );
  }
}

export default TodoList;

注释

  • TodoItem是一个展示组件,它接收一个todo对象作为props,并渲染出对应的文本和按钮。
  • TodoList是一个容器组件,它管理一个todos状态数组,并在渲染时遍历该数组,为每个todo项渲染一个TodoItem组件。

2. 高阶组件模式(Higher-Order Component Pattern, HOC)

描述
高阶组件是一个函数,它接收一个组件作为参数,并返回一个新的组件。这个新组件可以访问原始组件的props,并可以添加额外的props或行为。

示例代码

// 高阶组件:withLogging.js
import React from 'react';

const withLogging = (WrappedComponent) => {
  return class extends React.Component {
    componentDidMount() {
      console.log(`${WrappedComponent.name} mounted`);
    }

    componentWillUnmount() {
      console.log(`${WrappedComponent.name} will unmount`);
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
};

// 使用高阶组件的组件:EnhancedTodoItem.js
import React from 'react';
import withLogging from './withLogging';
import TodoItem from './TodoItem'; // 假设TodoItem是上面定义的展示组件

// 注意:这里我们实际上是在增强TodoItem组件,但为了示例清晰,我们假设有一个新的组件EnhancedTodoItem
const EnhancedTodoItem = withLogging(TodoItem);

// 通常情况下,你会直接使用EnhancedTodoItem而不是TodoItem
// 但在这个例子中,我们只是为了展示HOC的用法,所以EnhancedTodoItem和TodoItem功能相同,只是多了日志记录。

// 实际上,你可能会在EnhancedTodoItem中添加更多的逻辑或props。
export default EnhancedTodoItem;

注意:在上面的withLogging示例中,我们实际上没有直接对TodoItem进行增强(因为TodoItem已经是一个纯函数组件,并且没有额外的逻辑需要添加),但为了展示HOC的用法,我们假设有一个新的组件EnhancedTodoItem使用了这个HOC。在实际应用中,你会在HOC中添加额外的逻辑或props,并将其应用于需要增强的组件。

另外,由于TodoItem是一个函数组件,它没有name属性,所以console.log中的${WrappedComponent.name}可能不会显示你期望的名字。在实际应用中,你可能需要为函数组件添加一个displayName静态属性或使用其他方法来标识组件。

修正后的示例(为函数组件添加displayName):

// TodoItem.js(添加displayName)
import React from 'react';

const TodoItem = ({ todo }) => (
  // ...之前的代码
);

TodoItem.displayName = 'TodoItem'; // 添加displayName以便在日志中正确显示组件名

export default TodoItem;

这样,当使用withLogging高阶组件时,日志中就会正确地显示TodoItem mountedTodoItem will unmount

当然,除了之前提到的容器组件与展示组件模式和高阶组件模式外,React中还有其他常见的设计模式。以下是对这些模式的详细解析,并附上示例代码和注释:

3. 渲染属性模式(Render Props Pattern)

描述
渲染属性模式是一种将函数作为属性传递给组件的技术,该函数返回一个React元素。这种模式允许组件之间共享代码和逻辑。

示例代码

// MouseTracker.js
import React, { useState } from 'react';

const MouseTracker = ({ render }) => {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const handleMouseMove = (event) => {
    setPosition({ x: event.clientX, y: event.clientY });
  };

  return (
    <div style={{ height: '100vh' }} onMouseMove={handleMouseMove}>
      {render(position)}
    </div>
  );
};

export default MouseTracker;

// App.js
import React from 'react';
import MouseTracker from './MouseTracker';

const App = () => (
  <MouseTracker
    render={({ x, y }) => (
      <h1>鼠标的当前位置是 ({x}, {y})</h1>
    )}
  />
);

export default App;

注释

  • MouseTracker组件接收一个render属性,该属性是一个函数,它接收鼠标位置作为参数,并返回一个React元素。
  • App组件中,我们使用MouseTracker组件,并传递一个函数作为render属性,该函数根据鼠标位置渲染一个h1元素。

4. 自定义钩子模式(Custom Hook Pattern)

描述
自定义钩子允许你将组件逻辑提取到可重用的函数中。它们可以让你在不增加组件类的情况下复用状态逻辑。

示例代码

// useFetch.js
import { useState, useEffect } from 'react';

const useFetch = (url) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch(url)
      .then(response => {
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        return response.json();
      })
      .then(jsonData => {
        setData(jsonData);
        setLoading(false);
      })
      .catch(error => {
        setError(error);
        setLoading(false);
      });
  }, [url]);

  return { data, loading, error };
};

export default useFetch;

// DataDisplay.js
import React from 'react';
import useFetch from './useFetch';

const DataDisplay = ({ url }) => {
  const { data, loading, error } = useFetch(url);

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    <pre>
      {JSON.stringify(data, null, 2)}
    </pre>
  );
};

export default DataDisplay;

注释

  • useFetch是一个自定义钩子,它接收一个URL作为参数,并返回一个包含数据、加载状态和错误信息的对象。
  • DataDisplay组件使用useFetch钩子来获取数据,并根据加载状态和错误信息渲染相应的UI。

5. 组合模式(Composite Pattern)

描述
组合模式允许你将对象组合成树形结构以表示“部分-整体”的层次结构。在React中,这通常体现在组件树的设计上。

示例代码(简化版):

// Accordion.js
import React, { useState } from 'react';

const Accordion = ({ children }) => {
  const [activeIndex, setActiveIndex] = useState(null);

  const handleItemClick = (index) => {
    setActiveIndex(index);
  };

  return (
    <div>
      {React.Children.map(children, (child, index) =>
        React.cloneElement(child, {
          isActive: index === activeIndex,
          onItemClick: () => handleItemClick(index),
        })
      )}
    </div>
  );
};

// AccordionItem.js
import React from 'react';

const AccordionItem = ({ title, children, isActive, onItemClick }) => (
  <div>
    <h2 onClick={onItemClick}>{title}</h2>
    {isActive && <div>{children}</div>}
  </div>
);

export { Accordion, AccordionItem };

// App.js
import React from 'react';
import { Accordion, AccordionItem } from './Accordion';

const App = () => (
  <Accordion>
    <AccordionItem title="Item 1">Content 1</AccordionItem>
    <AccordionItem title="Item 2">Content 2</AccordionItem>
    <AccordionItem title="Item 3">Content 3</AccordionItem>
  </Accordion>
);

export default App;

注释

  • Accordion组件接收子组件(AccordionItem组件)作为参数,并管理哪个项目处于活动状态。
  • AccordionItem组件接收标题、子组件、活动状态和点击事件处理器作为props,并根据活动状态渲染内容。
  • App组件中,我们使用Accordion组件,并传递多个AccordionItem组件作为其子组件。

这些设计模式在React开发中非常常见,它们有助于提高代码的可维护性、可扩展性和重用性。


http://www.kler.cn/a/566831.html

相关文章:

  • Vue的data配置项
  • Go红队开发—语法补充
  • 迁移过程中,hive元数据字段校对
  • 在kubernetes集群中持续压测 SpringCloud 应用,pod 的 memory cache 持续增长问题
  • Mysql .idb文件 恢复
  • Windows10 Xming6 + Xshell7 实现远程 ubuntu-24.04.1-desktop gui 界面本地展示
  • Redis 同步机制详解
  • Docker 部署 Spring Cloud 项目:实战指南与经验分享
  • Djiang 5实用指南(八)后台管理系统
  • JSON-to-Excel v2.0.0发布,可以在Excel内部,把JSON转换成Excel格式,嵌套的JSON也能转
  • 5个GitHub热点开源项目!!
  • 【初阶数据结构】链表的柔光之美
  • 主流 AI 芯片配置
  • STM32之时钟树
  • Doris、ClickHouse 和 Flink 这三个技术典型的应用场景
  • 关于Hadoop集群部署打不开webUI界面问题
  • 软件安全性测试类型分享,第三方软件测试机构如何进行安全性测试?
  • 小智聊天机器人应用层头文件application.h解析
  • Django+Vue+数据可视化的网络考试与测评系统(程序+论文+讲解+安装+调试+售后)
  • DeepSeek系列 清华大学-AIGC发展研究3.0版 pdf完整版(附下载)