0

I want to implement conditional rendering in a functional React component. I don't know how to do this in a function.

I need the corresponding imported component to be rendered depending on the state.

I wrote this logic using the ternary operator and everything works, but this code is terrible and unreadable.

import React, { useState, useEffect } from "react";

import Header from "./header/header";
import Footer from "./footer/footer";

// One of these components will be rendered between Header and Footer ↓
// Name of the component in the state (activeItem)

import Landing from "./landing/landing";
import BookingManagement from "./bookingManagement/BookingManagement";
import BookingTickets from "./bookingTickets/bookingTickets";
import EnterProfile from "./enterProfile/enterProfile";
import PersonalArea from "./personalArea/personalArea";
import Register from "./register/register";
import SearchResults from "./searchResults/searchResults";
import ChoosePlace from "./choosePlace/choosePlace";

function App() {
  const [activeItem, setActiveItem] = useState("landing");

  useEffect(() => {
    console.log(activeItem);
  });

  return (
    <>
      <Header changeMain={setActiveItem} />
      {activeItem == "landing" ? <Landing changeMain={setActiveItem} /> : <></>}

      {activeItem == "bookingManagement" ? <BookingManagement /> : <></>}
      {activeItem == "bookingTickets" ? <BookingTickets /> : <></>}
      {activeItem == "enterProfile" ? <EnterProfile /> : <></>}
      {activeItem == "personalArea" ? <PersonalArea /> : <></>}
      {activeItem == "register" ? <Register /> : <></>}
      {activeItem == "searchResults" ? <SearchResults /> : <></>}

      {activeItem == "choosePlace" ? <ChoosePlace /> : <></>}

      <Footer changeMain={setActiveItem} />
    </>
  );
}

export default App;

I definitely need to implement this in the functional component, because I use hooks.

2
  • 2
    Why not a map of strings to components? Commented Nov 28, 2021 at 19:34
  • 2
    Looks like you might be looking for React Router Commented Nov 28, 2021 at 19:37

5 Answers 5

3

How about

const ComponentMap = {
  landing: Landing,
  bookingManagement: BookingManagement,
  bookingTickets: BookingTickets,
  enterProfile: EnterProfile,
  personalArea: PersonalArea,
  register: Register,
  searchResults: SearchResults,
  choosePlace: ChoosePlace
};

function App() {
  const [activeItem, setActiveItem] = useState("landing");

  useEffect(() => {
    console.log(activeItem);
  });

  const ActiveComponent = ComponentMap[activeItem] || React.Fragment;
  const ActiveComponentProps = {};
  if (activeItem === "landing") {
    ActiveComponentProps.changeMain = setActiveItem;
  }
  
  return (
    <>
      <Header changeMain={setActiveItem} />
      <ActiveComponent {...ActiveComponentProps} />
      <Footer changeMain={setActiveItem} />
    </>
  );
}
Sign up to request clarification or add additional context in comments.

Comments

1

You can create an object which wraps all your components and then use the correct component by using activeItem as the key:

    import React, {useState, useEffect} from 'react';

    import Header from './header/header';
    import Footer from './footer/footer';

    import Landing from './landing/landing';
    import BookingManagement from './bookingManagement/BookingManagement';
    import BookingTickets from './bookingTickets/bookingTickets';
    import EnterProfile from './enterProfile/enterProfile';
    import PersonalArea from './personalArea/personalArea';
    import Register from './register/register';
    import SearchResults from './searchResults/searchResults';
    import ChoosePlace from './choosePlace/choosePlace';

    const components = { Landing, BookingManagement, BookingTickets, EnterProfile, PersonalArea, Register, SearchResults, ChoosePlace };

    export default function App() {
      const [activeItem, setActiveItem] = useState("Landing");
      const ActiveItemComponent = components[activeItem];

      return (
        <>
          <Header changeMain={setActiveItem} />
          <ActiveItemComponent />
          <Footer changeMain={setActiveItem} />
        </>
      );
    }

Comments

1

you can go with react-router implementation. Or if you want to handle the same in this component you can do similar like below

const getComponent = () => {
  if (condition1) {
    return <Component1/>
  } else if (condition2) {
    return <Component2/>
  }
 
  return <DefaultComponent/>
}

and inside the render return you can call that function like below

return (
  {getComponent()}
)

Comments

1

instead of

{(activeItem=='landing' ? (
    <Landing changeMain={setActiveItem}/>
  ) : (
    <></>
  ))}

go with

{activeItem=='landing' && (
    <Landing changeMain={setActiveItem}/>
)}

2 Comments

While this omits the need of the : (else) part of the ternary operator's conditional rendering, it hardly fixes the core issue, which is repeated statements. It's much cleaner to simply have a map of the components and have the activeItem be the index to decide which component to render.
You are right! thank you for the remark 🙏
1
function App() {
    
    const [activeItem, setActiveItem] = useState('landing');
    
    const itemToComponent = [
      landing: {component: Landing},
      bookingManagement: {component: BookingManagement},
      ...
    ]
    const Components = itemToComponent[activeItem].component
    
  return (
    
      {<Components />}
          <Footer changeMain={setActiveItem}/>
       </>
  );
}

export default App;

1 Comment

Welcome to Stack Overflow. Code is a lot more helpful when it is accompanied by an explanation. Stack Overflow is about learning, not providing snippets to blindly copy and paste. Please edit your question and explain how it answers the specific question being asked. See How to Answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.