Home  Reactjs   Design patt ...

Design Patterns and approaches for writing React applications

There are several patterns and approaches for writing React applications, each suited to different needs and preferences. Here are some common patterns and architectural approaches:

1. Component-Based Architecture

React's core philosophy is component-based architecture. This involves building your UI with reusable, self-contained components. Each component manages its own state and props, and components are composed to build more complex UIs.

Example:

// Button Component
const Button = ({ onClick, children }) => (
  <button onClick={onClick}>{children}</button>
);

// App Component
const App = () => {
  const handleClick = () => alert('Button clicked');
  
  return (
    <div>
      <h1>Hello, World!</h1>
      <Button onClick={handleClick}>Click Me</Button>
    </div>
  );
};

2. Container/Presentational Pattern

In this pattern, components are divided into containers (which manage state and business logic) and presentational components (which handle the UI).

Example:

// Presentational Component
const TaskList = ({ tasks, onTaskClick }) => (
  <ul>
    {tasks.map(task => (
      <li key={task.id} onClick={() => onTaskClick(task.id)}>
        {task.name}
      </li>
    ))}
  </ul>
);

// Container Component
const TaskContainer = () => {
  const [tasks, setTasks] = useState([]);

  const fetchTasks = async () => {
    const response = await fetch('/tasks');
    const data = await response.json();
    setTasks(data);
  };

  useEffect(() => {
    fetchTasks();
  }, []);

  const handleTaskClick = (id) => {
    console.log(`Task ${id} clicked`);
  };

  return <TaskList tasks={tasks} onTaskClick={handleTaskClick} />;
};

3. Hook-Based Pattern

With the introduction of hooks, React now supports a more functional approach where you can use hooks to manage state, side effects, and context.

Example:

// Custom Hook
const useTasks = () => {
  const [tasks, setTasks] = useState([]);

  useEffect(() => {
    const fetchTasks = async () => {
      const response = await fetch('/tasks');
      const data = await response.json();
      setTasks(data);
    };

    fetchTasks();
  }, []);

  return tasks;
};

// Component Using Custom Hook
const TaskList = () => {
  const tasks = useTasks();

  return (
    <ul>
      {tasks.map(task => (
        <li key={task.id}>{task.name}</li>
      ))}
    </ul>
  );
};

4. Redux Pattern

Redux is a state management library often used in larger applications to manage global state. It uses a central store to manage the state of the application and actions to modify the state.

Example:

// Redux Store Setup
const initialState = { tasks: [] };

const tasksReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'SET_TASKS':
      return { ...state, tasks: action.payload };
    default:
      return state;
  }
};

// Component
const TaskList = () => {
  const dispatch = useDispatch();
  const tasks = useSelector(state => state.tasks);

  useEffect(() => {
    const fetchTasks = async () => {
      const response = await fetch('/tasks');
      const data = await response.json();
      dispatch({ type: 'SET_TASKS', payload: data });
    };

    fetchTasks();
  }, [dispatch]);

  return (
    <ul>
      {tasks.map(task => (
        <li key={task.id}>{task.name}</li>
      ))}
    </ul>
  );
};

5. Context API Pattern

The Context API allows you to pass data through the component tree without having to pass props down manually at every level.

Example:

// Create Context
const TaskContext = createContext();

// Provider Component
const TaskProvider = ({ children }) => {
  const [tasks, setTasks] = useState([]);

  useEffect(() => {
    const fetchTasks = async () => {
      const response = await fetch('/tasks');
      const data = await response.json();
      setTasks(data);
    };

    fetchTasks();
  }, []);

  return (
    <TaskContext.Provider value={tasks}>
      {children}
    </TaskContext.Provider>
  );
};

// Consumer Component
const TaskList = () => {
  const tasks = useContext(TaskContext);

  return (
    <ul>
      {tasks.map(task => (
        <li key={task.id}>{task.name}</li>
      ))}
    </ul>
  );
};

6. Component Composition

This pattern involves composing components together to build complex UIs. It’s different from the container/presentational pattern as it focuses on reusing and combining components rather than separating them.

Example:

// Card Component
const Card = ({ title, children }) => (
  <div className="card">
    <h2>{title}</h2>
    <div>{children}</div>
  </div>
);

// Using Card Component
const App = () => (
  <Card title="Task Details">
    <p>Details about the task go here.</p>
  </Card>
);

7. Atomic Design

This approach involves breaking down the UI into atoms (basic elements), molecules (combinations of atoms), organisms (combinations of molecules), templates, and pages. It helps in building a consistent design system.

Example:

// Atoms
const Button = ({ onClick, children }) => (
  <button onClick={onClick}>{children}</button>
);

// Molecules
const Form = () => (
  <form>
    <input type="text" placeholder="Name" />
    <Button>Submit</Button>
  </form>
);

// Organisms
const Header = () => (
  <header>
    <h1>My App</h1>
    <Form />
  </header>
);
Published on: Aug 01, 2024, 12:58 AM  
 

Comments

Add your comment