How to pass component as a prop and render it conditionally?

Viewed 400

I have a component here that gets an ID number and checks if that ID number exists in the database. If it exists, it should render a component and show an error message if not. Struggling with how I should write it, any help is appreciated.

function PatientIDInput({component}) {
  const [patientID, setPatientID] = useState('');
  const [errorMessage, setErrorMessage] = useState('');
  const [showComponent, setShowComponent] = useState(false);
  const [patientInformation, setPatientInformation] = useState('');

  const handleChange = (e) => {
    // some input change handling
  }

  const handleSubmit = (e) => {
    e.preventDefault();

    Physician.fetchPatientData(patientID)
      .then(res => {
        if (res.status === 200) {
            // show component if patient exists
        }
      })
      .catch(error => {
        if (error.response.status) {
          // set error if not
        }
      })
  }

  return (
    <>
    <form onSubmit={handleSubmit}>
               // some UI code for user's input
    </form>

    { showComponent 
      ? {Component patientInformation={patientInformation}} />  // this is where I'm 
                   struggling with the syntax. How should I write the logic? I want to pass
                   some props to the component too.
      : null}
    </>
  );
}

export default PatientIDInput;
3 Answers

Here are some patterns that I used most often.

Pass a "React Component"

function PatientIDInput({Component}) {
  // skip
  return (
    <>
    <form onSubmit={handleSubmit}>
               // some UI code for user's input
    </form>

    { showComponent 
      ? <Component patientInformation={patientInformation} />
      : null}
    </>
  );
}

export default PatientIDInput;
const Sample = ({ patientInformation }) => <div>{patientInformation}</div>
<PatientIDInput Component={Sample} />

Pass a "Render Function" as children

function PatientIDInput({children}) {
  // skip
  return (
    <>
    <form onSubmit={handleSubmit}>
               // some UI code for user's input
    </form>

    { showComponent 
      ? children({ patientInformation  })
      : null}
    </>
  );
}

export default PatientIDInput;
const Sample = ({ patientInformation }) => <div>{patientInformation}</div>
<PatientIDInput>
  {({ patientInformation }) => <Sample patientInformation ={patientInformation} />}
</PatientIDInput>

Pass a "React Element" as children

function PatientIDInput({children}) {
  // skip
  return (
    <>
    <form onSubmit={handleSubmit}>
               // some UI code for user's input
    </form>

    { showComponent 
      ? React.cloneElement(children, { patientInformation  })
      : null}
    </>
  );
}

export default PatientIDInput;
const Sample = ({ patientInformation }) => <div>{patientInformation}</div>
<PatientIDInput>
  <Sample/>
</PatientIDInput>

You can use

React.cloneElement(
  element,
  [config],
  [...children]
)

Clone and return a new React element using element as the starting point. config should contain all new props, key, or ref. The resulting element will have the original element’s props with the new props merged in shallowly. New children will replace existing children. key and ref from the original element will be preserved if no key and ref present in the config.

Example

import React from "react";

function Child(props) {
  return <div>{props.name}</div>;
}

function SomeOtherComponent(props) {
  return (
    <>
      {React.cloneElement(props.component, {
        someFunction: () => {
          console.log("inside callback");
        },
        name: "Ganesh",
      })}
    </>
  );
}

function App() {
  return (
    <div>
      Hi
      <SomeOtherComponent component={<Child />}></SomeOtherComponent>
    </div>
  );
}

Instead of passing component as props import the component directly inside PatientIdInput component and pass the patientInformation as props to it like this:

**Import your Component Here**

function PatientIDInput({component}) {
  const [patientID, setPatientID] = useState('');
  const [errorMessage, setErrorMessage] = useState('');
  const [showComponent, setShowComponent] = useState(false);
  const [patientInformation, setPatientInformation] = useState('');

At the return part:

 return (
   <>
    <form onSubmit={handleSubmit}>
           // some UI code for user's input
    </form>

  { showComponent 
    ? <ImportedComponent patientInformation={patientInformation}/>
  : null}
</>
  );
}

export default PatientIDInput;
Related