”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > ReactJS 设计模式:编写健壮且可扩展的组件

ReactJS 设计模式:编写健壮且可扩展的组件

发布于2024-11-07
浏览:464

ReactJS Design Patterns: Writing Robust and Scalable Components

ReactJS 中的设计模式为应用程序开发中的常见问题提供了标准化且经过验证的解决方案。使用这些模式不仅使您的代码更具可读性和可维护性,而且还增强了其可扩展性和健壮性。让我们深入研究一些最流行的 ReactJS 设计模式,并通过示例来说明它们的用法。

1. 容器和展示组件模式

容器和展示模式将组件分为两类:

  • 展示组件:关注事物的外观(UI)。
  • 容器组件:关注事物如何工作(逻辑和状态管理)。

这种分离可以实现更好的可重用性、更容易的测试和更清晰的代码。

示例:展示组件和容器组件

// Presentational Component: Displaying User List (UserList.js)
import React from 'react';

const UserList = ({ users }) => (
  
    {users.map((user) => (
  • {user.name}
  • ))}
); export default UserList;
// Container Component: Fetching User Data (UserContainer.js)
import React, { useState, useEffect } from 'react';
import UserList from './UserList';

const UserContainer = () => {
  const [users, setUsers] = useState([]);

  useEffect(() => {
    const fetchUsers = async () => {
      const response = await fetch('https://jsonplaceholder.typicode.com/users');
      const data = await response.json();
      setUsers(data);
    };
    fetchUsers();
  }, []);

  return ;
};

export default UserContainer;

这里,UserList 是一个展示组件,它接收用户作为 props,而 UserContainer 则处理数据获取和状态管理。

2. 高阶组件(HOC)模式

A 高阶组件 (HOC) 是一个将组件作为参数并返回新组件的函数。 HOC 通常用于横切关注点,例如身份验证、日志记录或增强组件行为。

示例:创建 HOC 进行授权

// withAuthorization.js (HOC for Authorization)
import React from 'react';

const withAuthorization = (WrappedComponent) => {
  return class extends React.Component {
    componentDidMount() {
      if (!localStorage.getItem('authToken')) {
        // Redirect to login if not authenticated
        window.location.href = '/login';
      }
    }

    render() {
      return ;
    }
  };
};

export default withAuthorization;
// Dashboard.js (Component Wrapped with HOC)
import React from 'react';
import withAuthorization from './withAuthorization';

const Dashboard = () => 

Welcome to the Dashboard

; export default withAuthorization(Dashboard);

通过使用 withAuthorization 包装 Dashboard,您可以确保只有经过身份验证的用户才能访问它。

3. 渲染道具模式

Render Props 模式涉及使用值为函数的 prop 在组件之间共享代码。此模式对于基于某些条件或状态的动态渲染非常有用。

示例:使用渲染道具进行鼠标跟踪

// MouseTracker.js (Component with Render Props)
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 
{render(position)}
; }; export default MouseTracker;
// App.js (Using Render Props)
import React from 'react';
import MouseTracker from './MouseTracker';

const App = () => (
   (
      

Mouse position: ({x}, {y})

)} /> ); export default App;

MouseTracker 组件使用 render prop 将鼠标位置数据传递给任何组件,使其具有高度可重用性。

4. 自定义 Hooks 模式

自定义 Hooks 允许您跨多个组件封装和重用有状态逻辑。这种模式促进了代码的可重用性和清晰的关注点分离。

示例:创建用于获取数据的自定义挂钩

// useFetch.js (Custom Hook)
import { useState, useEffect } from 'react';

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

  useEffect(() => {
    const fetchData = async () => {
      const response = await fetch(url);
      const result = await response.json();
      setData(result);
      setLoading(false);
    };
    fetchData();
  }, [url]);

  return { data, loading };
};

export default useFetch;
// App.js (Using the Custom Hook)
import React from 'react';
import useFetch from './useFetch';

const App = () => {
  const { data, loading } = useFetch('https://jsonplaceholder.typicode.com/posts');

  if (loading) return 
Loading...
; return (
    {data.map((post) => (
  • {post.title}
  • ))}
); }; export default App;

useFetch自定义hook封装了数据获取逻辑,可以在不同组件之间复用。

5. 复合组件模式

复合组件模式允许组件一起工作来管理状态和行为。此模式对于构建复杂的 UI 组件(如选项卡、手风琴或下拉菜单)非常有用。

示例:使用复合组件构建选项卡

// Tabs.js (Parent Component)
import React, { useState } from 'react';

const Tabs = ({ children }) => {
  const [activeIndex, setActiveIndex] = useState(0);

  return React.Children.map(children, (child, index) =>
    React.cloneElement(child, { isActive: index === activeIndex, setActiveIndex, index })
  );
};

const Tab = ({ children, isActive, setActiveIndex, index }) => (
  
);

const TabPanel = ({ children, isActive }) => (isActive ? 
{children}
: null); Tabs.Tab = Tab; Tabs.TabPanel = TabPanel; export default Tabs;
// App.js (Using Compound Components)
import React from 'react';
import Tabs from './Tabs';

const App = () => (
  Tab 1Tab 2Content for Tab 1Content for Tab 2
);

export default App;

Tabs 组件管理状态,而 Tab 和 TabPanel 组件协同工作来显示选项卡式内容。

6. 受控和非受控组件模式

受控组件完全由 React 状态管理,而非受控组件则依赖 DOM 来获取其状态。两者都有其用途,但为了一致性和可维护性,受控组件通常是首选。

示例:受控组件与非受控组件

// Controlled Component (TextInputControlled.js)
import React, { useState } from 'react';

const TextInputControlled = () => {
  const [value, setValue] = useState('');

  return (
     setValue(e.target.value)} />
  );
};

export default TextInputControlled;
// Uncontrolled Component (TextInputUncontrolled.js)
import React, { useRef } from 'react';

const TextInputUncontrolled = () => {
  const inputRef = useRef();

  const handleClick = () => {
    console.log(inputRef.current.value);
  };

  return (
    
      
    >
  );
};

export default TextInputUncontrolled;

在受控组件中,React 完全控制表单状态,而在非受控组件中,状态由 DOM 本身管理。

7. Hooks 工厂模式

Hooks Factory 模式涉及创建动态生成和管理多个状态或行为的钩子,提供灵活的方式来管理复杂逻辑。

示例:使用 Hooks Factory 进行动态状态管理

// useDynamicState.js (Hook Factory)
import { useState } from 'react';

const useDynamicState = (initialStates) => {
  const states = {};
  const setters = {};

  initialStates.forEach(([key, initialValue]) => {
    const [state, setState] = useState(initialValue);
    states[key] = state;
    setters[key] = setState;
  });

  return [states, setters];
};

export default useDynamicState;
// App.js (Using the Hooks Factory)
import React from 'react';
import useDynamicState from './useDynamicState';

const App = () => {
  const [states, setters] = useDynamicState([
    ['name', ''],
    ['age', 0],
  ]);

  return (
    
setters .name(e.target.value)} /> setters.age(parseInt(e.target.value))} />

Name: {states.name}

Age: {states.age}

); }; export default App;

这个钩子工厂动态创建和管理多个状态,提供灵活性和更清晰的代码。

结论

通过利用这些设计模式,您可以创建更健壮、可扩展和可维护的 React 应用程序。这些模式可帮助您编写符合最佳实践的干净、可重用的代码,确保您的应用程序随着时间的推移更容易开发和管理。

您想更深入地研究这些模式或探索其他主题吗?

版本声明 本文转载于:https://dev.to/abhishek_kumar_d9009a7ae6/reactjs-design-patterns-writing-robust-and-scalable-components-2a6h?1如有侵犯,请联系[email protected]删除
最新教程 更多>
  • 您能否在 C++ 中实现高效的二分搜索算法,将迭代器返回到搜索结果?
    您能否在 C++ 中实现高效的二分搜索算法,将迭代器返回到搜索结果?
    在 C 中搜索高效的二分搜索算法 程序员经常寻求实现高效的二分搜索算法,以提供对数时间复杂度的优势。一个常见的要求是算法返回一个指向搜索结果的迭代器,而不是一个指示其存在的简单布尔值。C 标准库在 标头中提供了 std::binary_search,但它仅返回一个布尔值。正如提问者所指出的,对于需...
    编程 发布于2024-11-08
  • 使用 Javascript 的心形图案代码
    使用 Javascript 的心形图案代码
    代码 let heart = ""; let size = 6; // Loop to print upper part of the heart for (let i = size / 2; i <= size; i = 2) { for (let j = 1; ...
    编程 发布于2024-11-08
  • 如何在 Chrome DevTools 中轻松识别和监控表单元素事件?
    如何在 Chrome DevTools 中轻松识别和监控表单元素事件?
    了解元素交互触发的事件要在可自定义表单元素上正确识别和处理事件,必须了解交互时触发的特定事件。 Chrome DevTools 提供了一个强大的工具,monitorEvents,来协助完成此过程。使用 monitorEvents()检查目标元素: 右键单击​​该元素并选择“Inspect”或在 De...
    编程 发布于2024-11-08
  • 为什么Go不支持传统继承?
    为什么Go不支持传统继承?
    Go中的继承Go为什么不支持传统类型继承?传统类型继承,即子类继承一个或多个父类的定义,不是 Go 编程语言的一项功能。创建者的基本原理在 Go 语言中FAQ,语言创建者解释说,面向对象的编程语言通常强调定义类型之间的关系,这些关系在 Go 中可以自动推断。 Go 类型不会显式指定类型关系,而是自动...
    编程 发布于2024-11-08
  • 如何在 Python 中创建虚拟环境
    如何在 Python 中创建虚拟环境
    Python 虚拟环境对于管理依赖关系和避免项目之间的冲突至关重要。本指南将引导您完成在 Python 中创建和激活虚拟环境的过程。 第 1 步:导航到您的项目目录 打开终端并导航到要设置 Python 虚拟环境的目录。您可以使用 cd 命令来执行此操作: cd /path/to/y...
    编程 发布于2024-11-08
  • 如何在 Go JSON 解组中处理嵌套数组?
    如何在 Go JSON 解组中处理嵌套数组?
    Golang JSON:通过解组处理嵌套数组在 Go 中,在解组后处理嵌套 JSON 数组时,理解错误至关重要“类型接口{}不支持索引。”当您尝试访问存储在interface{}变量中的JSON数组中的元素时,会出现此错误。要解决此问题,您需要利用类型断言将interface{}变量转换为底层数组类...
    编程 发布于2024-11-08
  • 如何在 Java 中组合路径
    如何在 Java 中组合路径
    组合 Java 中的路径C#/.NET 中的 System.IO.Path.Combine 方法允许将多个路径段组合成一个单一、有效的路径。 Java 提供了实现类似功能的替代方法。Path Object在 Java 7 及更高版本中,建议使用 java.nio.file.Path 类进行路径操作。...
    编程 发布于2024-11-08
  • 有效 JSON 有哪些不同的定义?
    有效 JSON 有哪些不同的定义?
    理解最小有效 JSONJSON 的概念已在各种 RFC 和规范中广泛讨论。 RFC4627 最初将 JSON 定义为序列化对象或数组。根据此定义,仅 {}(空对象) 和 [](空数组) 符合有效、完整的 JSON 字符串的条件。但是,ECMA-404引入了一项修正案,扩大了有效 JSON 字符串的范...
    编程 发布于2024-11-08
  • 使用 MapStruct 映射继承层次结构
    使用 MapStruct 映射继承层次结构
    Intro MapStruct provides a rich set of features for mapping Java types. The technical documentation describes extensively the classes and ann...
    编程 发布于2024-11-08
  • 可以处理变量的 ID 以访问 Python 中的对象吗?
    可以处理变量的 ID 以访问 Python 中的对象吗?
    变量的 ID 可以取消引用吗?在 Python 中,id() 函数返回对象的唯一标识符。这个标识符可以存储在变量中,但是这个变量的ID可以解引用吗?从学术角度来看,答案是肯定的。 _ctypes 模块提供了一个函数 PyObj_FromPtr(),可以将指针转换为 Python 对象。使用此函数,我...
    编程 发布于2024-11-08
  • 为什么 imagecreatefrompng() 产生黑色背景而不是透明区域?
    为什么 imagecreatefrompng() 产生黑色背景而不是透明区域?
    imagecreatefrompng() 生成黑色背景而不是透明区域?在 PHP 中,imagecreatefrompng() 函数通常用于处理 PNG图像。然而,据观察,使用此函数时,PNG 透明度可能会转换为纯黑色。要解决此问题,可以在使用 imagecreatetruecolor() 创建新画...
    编程 发布于2024-11-08
  • Go反射中reflect.Type和reflect.Value的主要区别是什么?
    Go反射中reflect.Type和reflect.Value的主要区别是什么?
    Go 中的反射类型和值Go 中的反射允许开发人员在运行时检查和操作类型和值。了解它们的区别对于有效使用反射至关重要。反射中的类型与值在反射中,reflect.TypeOf(i) 返回一个reflect.Type 对象,而reflect.ValueOf(i)返回一个reflect.Value obje...
    编程 发布于2024-11-08
  • 如何在 AngularJS 中安全地设置变量的 iframe src 属性?
    如何在 AngularJS 中安全地设置变量的 iframe src 属性?
    在 AngularJS 中从变量设置 iframe src 属性在 AngularJS 中,尝试从以下位置设置 iframe 的 src 属性时可能会遇到问题一个变量。为了解决这个问题,这里有一个分步指南:1。注入 $sce 服务将 $sce(严格上下文转义)服务注入控制器以处理清理。functio...
    编程 发布于2024-11-08
  • 为什么我的 KeyListener 无法在 JPanel 中工作?
    为什么我的 KeyListener 无法在 JPanel 中工作?
    JPanel 中 KeyListeners 无响应:常见问题当使用 KeyListeners 检测 JPanel 中的击键时,开发人员经常遇到这样的问题:侦听器无法触发所需的操作。此问题可能由多个因素引起。焦点组件约束KeyListener 依赖将自身附加到焦点组件才能正常运行。默认情况下,焦点不会...
    编程 发布于2024-11-08
  • 从 React 到 React Native 的旅程
    从 React 到 React Native 的旅程
    作为一名 React / JS 开发人员,您可能有这样的想法 “我应该学习 React Native 吗?” 这是一个公平的问题,也是我几年前问自己的问题。事实证明,学习 React Native 绝对是正确的决定。这让我成为了亚马逊的高级开发倡导者,我现在使用 React Native 跨 And...
    编程 发布于2024-11-08

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3