ホームページ  >  記事  >  ウェブフロントエンド  >  ReactJS デザイン パターン: 堅牢でスケーラブルなコンポーネントの作成

ReactJS デザイン パターン: 堅牢でスケーラブルなコンポーネントの作成

WBOY
WBOYオリジナル
2024-09-10 14:30:42284ブラウズ

ReactJS Design Patterns: Writing Robust and Scalable Components

ReactJS のデザイン パターンは、アプリケーション開発における一般的な問題に対する標準化された実証済みのソリューションを提供します。これらのパターンを使用すると、コードが読みやすく保守しやすくなるだけでなく、コードのスケーラビリティと堅牢性も向上します。最も人気のある ReactJS 設計パターンのいくつかを、その使用法を示す例とともに詳しく見ていきましょう。

1. コンテナとプレゼンテーションコンポーネントのパターン

コンテナとプレゼンテーションのパターンは、コンポーネントを 2 つのカテゴリに分けます:

  • プレゼンテーション コンポーネント: 物事の見た目 (UI) に焦点を当てます。
  • コンテナコンポーネント: 物事がどのように機能するか (ロジックと状態管理) に焦点を当てます。

この分離により、再利用性が向上し、テストが容易になり、コードがクリーンになります。

例: プレゼンテーションコンポーネントとコンテナコンポーネント

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

const UserList = ({ users }) => (
  <ul>
    {users.map((user) => (
      <li key={user.id}>{user.name}</li>
    ))}
  </ul>
);

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 <UserList users={users} />;
};

export default UserContainer;

ここで、UserList はユーザーを小道具として受け取るプレゼンテーション コンポーネントであり、UserContainer はデータのフェッチと状態管理を処理します。

2. 高次コンポーネント (HOC) パターン

高次コンポーネント (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 <WrappedComponent {...this.props} />;
    }
  };
};

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

const Dashboard = () => <h1>Welcome to the Dashboard</h1>;

export default withAuthorization(Dashboard);

withAuthorization でダッシュボードをラップすると、認証されたユーザーのみがダッシュボードにアクセスできるようになります。

3. 小道具パターンをレンダリング

Render Props パターンには、値が関数であるプロップを使用してコンポーネント間でコードを共有することが含まれます。このパターンは、特定の条件または状態に基づいた動的レンダリングに役立ちます。

例: マウス追跡にレンダー プロップを使用する

// 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 <div onMouseMove={handleMouseMove}>{render(position)}</div>;
};

export default MouseTracker;
// App.js (Using Render Props)
import React from 'react';
import MouseTracker from './MouseTracker';

const App = () => (
  <MouseTracker
    render={({ x, y }) => (
      <h1>
        Mouse position: ({x}, {y})
      </h1>
    )}
  />
);

export default App;

MouseTracker コンポーネントは、レンダー プロップを使用してマウスの位置データを任意のコンポーネントに渡すため、再利用性が高くなります。

4. カスタムフックパターン

カスタム フックを使用すると、複数のコンポーネント間でステートフル ロジックをカプセル化して再利用できます。このパターンは、コードの再利用性と懸念事項の明確な分離を促進します。

例: データをフェッチするためのカスタム フックの作成

// 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 <div>Loading...</div>;

  return (
    <ul>
      {data.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
};

export default App;

useFetch カスタム フックは、さまざまなコンポーネント間で再利用できるデータ フェッチ ロジックをカプセル化します。

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 }) => (
  <button onClick={() => setActiveIndex(index)}>{children}</button>
);

const TabPanel = ({ children, isActive }) => (isActive ? <div>{children}</div> : 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 = () => (
  <Tabs>
    <Tabs.Tab>Tab 1</Tabs.Tab>
    <Tabs.Tab>Tab 2</Tabs.Tab>
    <Tabs.TabPanel>Content for Tab 1</Tabs.TabPanel>
    <Tabs.TabPanel>Content for Tab 2</Tabs.TabPanel>
  </Tabs>
);

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 (
    <input type="text" value={value} onChange={(e) => 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 (
    <>
      <input type="text" ref={inputRef} />
      <button onClick={handleClick}>Log Input Value</button>
    </>
  );
};

export default TextInputUncontrolled;

制御されたコンポーネントでは、React がフォームの状態を完全に制御しますが、制御されていないコンポーネントでは、状態は DOM 自体によって管理されます。

7. フックファクトリーパターン

フック ファクトリ パターンには、複数の状態や動作を動的に生成および管理するフックの作成が含まれ、複雑なロジックを管理する柔軟な方法が提供されます。

例: フックファクトリーを使用した動的状態管理

// 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 (
    <div>
      <input
        type="text"
        value={states.name}
        onChange={(e) => setters

.name(e.target.value)}
      />
      <input
        type="number"
        value={states.age}
        onChange={(e) => setters.age(parseInt(e.target.value))}
      />
      <p>Name: {states.name}</p>
      <p>Age: {states.age}</p>
    </div>
  );
};

export default App;

このフック ファクトリは複数の状態を動的に作成および管理し、柔軟性とクリーンなコードを提供します。

結論

これらの設計パターンを活用することで、より堅牢でスケーラブルで保守しやすい React アプリケーションを作成できます。これらのパターンは、ベスト プラクティスに準拠したクリーンで再利用可能なコードを作成するのに役立ち、長期にわたってアプリケーションの開発と管理が容易になります。

これらのパターンのいずれかをさらに深く掘り下げて検討しますか?

以上がReactJS デザイン パターン: 堅牢でスケーラブルなコンポーネントの作成の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
前の記事:安全な割り当て次の記事:安全な割り当て