React LogoConditional Rendering and Lists in React

Conditional Rendering

Conditional rendering in React allows you to render different elements or components based on certain conditions. This is a fundamental concept for building dynamic user interfaces where parts of the UI need to appear, disappear, or change based on application state, user input, or data availability. React offers several ways to implement conditional rendering:

1. `if`/`else` statements: You can use standard JavaScript `if`/`else` statements within your component logic to return different JSX based on a condition. This is often used outside the `return` statement or to return an entire component.
```jsx
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <h1>Welcome back!</h1>;
} else {
return <h1>Please sign up.</h1>;
}
}
```

2. Ternary Operator (`condition ? expression_if_true : expression_if_false`): This is a concise way to render one of two expressions conditionally, often used inline within JSX when you need to switch between two different pieces of UI.
```jsx
function Status({ isActive }) {
return (
<p>
User is {isActive ? 'Active' : 'Inactive'}
</p>
);
}
```

3. Logical `&&` Operator (`condition && expression_if_true`): If you only want to render something when a condition is true, and render nothing otherwise (or `null`), you can use the logical `&&` operator. In JavaScript, `true && expression` evaluates to `expression`, and `false && expression` evaluates to `false`. React treats `false`, `null`, `undefined`, and `true` as non-renderable values (it will render nothing).
```jsx
function Notifications({ unreadCount }) {
return (
<div>
{unreadCount > 0 &&
<p>You have {unreadCount} unread messages.</p>
}
</div>
);
}
```

4. Returning `null`: A component can return `null` to prevent itself from rendering anything. This is useful when a component's rendering is entirely dependent on a condition.
```jsx
function WarningBanner({ warn }) {
if (!warn) {
return null;
}
return (
<div className="warning">
Warning!
</div>
);
}
```

Lists

Rendering lists of data is a common task in React. You typically use the JavaScript `map()` array method to iterate over an array of data and return a list of React elements. Each item in the list should have a unique `key` prop.

1. `map()` method: The `map()` method creates a new array by calling a provided function on every element in the calling array. In React, you use it to transform an array of data into an array of JSX elements.
```jsx
const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) =>
<li>{number}</li>
);
// To be rendered inside a <ul> or <ol>
```

2. `key` prop: The `key` prop is crucial when rendering lists. It helps React identify which items have changed, are added, or are removed. Keys should be unique among siblings. Without a stable and unique key, React might have trouble re-rendering lists efficiently and correctly, leading to potential performance issues or incorrect UI state.
* Best practice: Use a stable ID from your data (e.g., `item.id`).
* Avoid: Using array index as a `key` if the order of items can change, items can be added/removed, or if the list items have internal state. It's generally safe only for static lists where items don't change order or content.

Combining Conditional Rendering and Lists

You often need to combine these two concepts. This can involve:

* Conditionally rendering the entire list: Show the list only if there's data, otherwise display a 'no items' message.
* Conditionally rendering items within a list: Display specific elements or apply styles to individual list items based on conditions related to that item's data.
* Conditionally filtering items before rendering: Use `filter()` before `map()` to only render items that meet certain criteria.

By leveraging these techniques, you can create highly interactive and responsive UIs that adapt to various data states and user interactions.

Example Code

import React from 'react';

// Sample data for users
const usersData = [
  { id: 1, name: 'Alice', email: 'alice@example.com', isActive: true, role: 'Admin' },
  { id: 2, name: 'Bob', email: 'bob@example.com', isActive: false, role: 'User' },
  { id: 3, name: 'Charlie', email: 'charlie@example.com', isActive: true, role: 'User' },
  { id: 4, name: 'Diana', email: 'diana@example.com', isActive: true, role: 'Editor' },
];

function UserList({
  users,
  showEmail,
  showActiveStatus,
  filterByRole = null,
}) {
  // 1. Conditional Rendering for the entire list (empty state)
  if (!users || users.length === 0) {
    return <p>No users to display.</p>;
  }

  // 2. Conditionally filter users before mapping
  const filteredUsers = filterByRole
    ? users.filter((user) => user.role === filterByRole)
    : users;

  if (filteredUsers.length === 0) {
    return <p>No users found for the role: {filterByRole}.</p>;
  }

  return (
    <div>
      <h2>User List ({filterByRole ? `Role: ${filterByRole}` : 'All'})</h2>
      <ul>
        {filteredUsers.map((user) => (
          // 3. Rendering a list with unique 'key' prop
          <li key={user.id} className={user.isActive ? 'active-user' : 'inactive-user'}>
            <strong>{user.name}</strong> (Role: {user.role})

            {/* 4. Conditional Rendering for individual list item properties (Logical &&) */}
            {showEmail && <p>Email: {user.email}</p>}

            {/* 5. Conditional Rendering for different content based on a condition (Ternary Operator) */}
            {showActiveStatus ? (
              <span className={user.isActive ? 'badge-active' : 'badge-inactive'}>
                Status: {user.isActive ? 'Active' : 'Inactive'}
              </span>
            ) : (
              <span className="badge-info">Status display disabled</span>
            )}

            {/* Example: Conditionally render a 'Manager' badge for Admins */}
            {user.role === 'Admin' && <span className="badge-admin">Admin User!</span>}
          </li>
        ))}
      </ul>
    </div>
  );
}

// Main App component to demonstrate usage
function App() {
  return (
    <div className="App">
      <h1>React Conditional Rendering and Lists Demo</h1>

      <div className="section">
        <h3>Displaying All Users</h3>
        <UserList users={usersData} showEmail={true} showActiveStatus={true} />
      </div>

      <div className="section">
        <h3>Displaying Active Users Only (Filtered within component, but showing how to pass props)</h3>
        {/* For this example, filtering is done based on role prop. 
            To filter by isActive, you'd modify UserList's filter logic 
            or pass already filtered data. */}
        <UserList
          users={usersData.filter(user => user.isActive)}
          showEmail={false}
          showActiveStatus={true}
        />
      </div>

      <div className="section">
        <h3>Displaying Users with Role 'User' (Filtered by prop)</h3>
        <UserList users={usersData} showEmail={true} showActiveStatus={false} filterByRole="User" />
      </div>

      <div className="section">
        <h3>Displaying Users with Role 'Guest' (No matching users)</h3>
        <UserList users={usersData} showEmail={true} showActiveStatus={true} filterByRole="Guest" />
      </div>

      <div className="section">
        <h3>Displaying Empty List State</h3>
        <UserList users={[]} showEmail={true} showActiveStatus={true} />
      </div>
    </div>
  );
}

export default App;

// Basic CSS for better visualization (can be in App.css or a style tag)
/*
.App {
  font-family: sans-serif;
  padding: 20px;
}

.section {
  margin-bottom: 30px;
  padding: 15px;
  border: 1px solid #eee;
  border-radius: 8px;
  background-color: #f9f9f9;
}

h2 {
  color: #333;
  border-bottom: 1px solid #ccc;
  padding-bottom: 5px;
  margin-top: 0;
}

ul {
  list-style: none;
  padding: 0;
}

li {
  background-color: #fff;
  border: 1px solid #ddd;
  margin-bottom: 10px;
  padding: 10px;
  border-radius: 5px;
  display: flex;
  flex-direction: column;
}

li.active-user {
  border-left: 5px solid #4CAF50;
}

li.inactive-user {
  border-left: 5px solid #f44336;
  opacity: 0.8;
}

li p {
  margin: 5px 0;
  color: #555;
}

.badge-active {
  background-color: #d4edda;
  color: #155724;
  padding: 3px 8px;
  border-radius: 12px;
  font-size: 0.8em;
  margin-top: 5px;
  align-self: flex-start;
}

.badge-inactive {
  background-color: #f8d7da;
  color: #721c24;
  padding: 3px 8px;
  border-radius: 12px;
  font-size: 0.8em;
  margin-top: 5px;
  align-self: flex-start;
}

.badge-info {
  background-color: #cfe2ff;
  color: #052c65;
  padding: 3px 8px;
  border-radius: 12px;
  font-size: 0.8em;
  margin-top: 5px;
  align-self: flex-start;
}

.badge-admin {
  background-color: #ffebcc;
  color: #663d00;
  padding: 3px 8px;
  border-radius: 12px;
  font-size: 0.8em;
  margin-top: 5px;
  align-self: flex-start;
  font-weight: bold;
}
*/