RahafMa
RahafMa

Reputation: 43

react js render differnet component based on button click

so i have this logic where user click a button then based on the clicked button different component get rendered I was wondering if there is a better method to implement this logic

function Test(props) {

    const [component, setComponent] = useState("createPatient")
    const [rendered, setRendered] = useState()

    function clickHandler(component) {
        switch (component) {
            case "createPatient":
                setRendered(<PatientForm/>)
                break
            case "findPatient":
                setRendered(<FindPatient/>)
                break
            case "patientsList":
                setRendered(<PatientListTable/>)

        }
    }

    return (
        <div>

            <button onClick={() => clickHandler("createPatient")}>Create Patient</button>
            <button onClick={() => clickHandler("findPatient")}>Find Patient</button>
            <button onClick={() => clickHandler("patientsList")}>Patients List</button>


            { rendered  }
        </div>
    );
}

export default Test;

Upvotes: 4

Views: 3118

Answers (3)

Ajin Kabeer
Ajin Kabeer

Reputation: 2186

All the other answers here are correct and work well for your use case. I would like to take it a step further and introduce you to code-splitting. It is not necessary but you can always try it.

Presently, you are loading all the components you need at once when your Test component is loaded. If your imported components in the future get big or complex, the initial rendering can be slowed down.

Code splitting allows you to split your code into small chunks which you can then load on demand.

Here is a working sandbox.

import React, { useState } from "react";

function Test() {
  const [component, setComponent] = useState(null);

  const LoadComponent = async location => {
    const { default: component } = await import(`./components/${location}`);
    setComponent(component);
  };

  return (
    <div>
      <h1>Click the button to proceed</h1>
      <button onClick={() => LoadComponent("PatientForm")}>
        Create Patient
      </button>
      <button onClick={() => LoadComponent("FindPatient")}>
        Find Patient
      </button>
      <button onClick={() => LoadComponent("PatientListTable")}>
        Patients List
      </button>
      {component}
    </div>
  );
}

export default Test;

If you are using the latest version of React, you can use React.lazy. You'll also need to wrap this lazy component with Suspense. You can modify the above code like this to load components with React.lazy.

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

const LoadComponent = location => {
    const Component = React.lazy(() => import(`./components/${location}`));
    setComponent(<Component />);
  };

return <Suspense fallback={<div>Loading...</div>}>{component}</Suspense>

Always think in terms of how you can ship the least amount of JavaScript to the user.

Upvotes: 5

Mechanic
Mechanic

Reputation: 5380

the other logic available are roughly similar and doesn't make much of a different in the end result, mostly stylistic and vary in readability; here are two alternative ways;

function Test(props) {
const [index, setIndex] = useState(0);
const components = [<PatientForm/>, <FindPatient/>, <PatientListTable/>];

return (
  <div>
     <button onClick={() => setIndex(0)}>Patient Form</button>
     <button onClick={() => setIndex(1)}>Find Patient</button>
     <button onClick={() => setIndex(2)}>Patients List</button>
    {components[index]}
  </div>
)

or using boolean approach to render components; something like this;

function Test(props) {
const [step, setStep] = useState(0);

return (
  <div>
     <button onClick={() => setStep(0)}>Patient Form</button>
     <button onClick={() => setStep(1)}>Find Patient</button>
     <button onClick={() => setStep(2)}>Patients List</button>
     {step == 0 && <PatientForm/>}
     {step == 1 && <FindPatient/>}
     {step == 2 && <PatientListTable/>}
  </div>
)

you get the idea

Upvotes: 1

gautamits
gautamits

Reputation: 1292

No need to keep components in state, instead you can directly render them using conditionals.

function Test(props) {

    const [component, setComponent] = useState("createPatient")

    function clickHandler(component) {
        switch (component) {
            case "createPatient":
                setComponent('createPatient)
                break
            case "findPatient":
                setComponent('findPatient')
                break
            case "patientsList":
               setComponent('patientsList')

        }
    }

    return (
        <div>

            <button onClick={() => clickHandler("createPatient")}>Create Patient</button>
            <button onClick={() => clickHandler("findPatient")}>Find Patient</button>
            <button onClick={() => clickHandler("patientsList")}>Patients List</button>

         {component === 'createPateient' && <PatientForm/>}
         {component === 'findPatient' && <FindPatient/>}
         {component === 'patientsLis' && <PatientListTable/>}
           
        </div>
    );
}

export default Test;

Upvotes: 0

Related Questions