reactjsreact-functional-componentstate-managementconditional-rendering

How to pass a component and state value in React to render conditional data based on user selection?


I am working on a React project where I have two components, UserRules (Component A) and UserEmail (Component B). I need to pass the value of a state variable selectedVoucherOption from Component A to Component B so that I can render specific data in Component B based on the selected option.

Here’s what I am doing:

In UserRules (Component A), I’ve added Line A because I want to pass the value of selectedVoucherOption to Component B (UserEmail) to render the data conditionally based on the user's selection.

Component A:

function UserRules({ intl, home, dispatch }) {
  const [selectedVoucherOption, setSelectedVoucherOption] = useState(null);

  return (
    <Row>
      <Col xs={12}>
        <Label required>{intl.formatMessage({ ...messages.voucherOptions.header })}</Label>
        <Dropdown
          options={voucherOptions}
          placeholder={intl.formatMessage({ ...messages.voucherOptions.placeholder })}
          onChange={(_evt, obj) => {
            setSelectedVoucherOption(obj);
            UserEmail; // Line A: Trying to pass the value here
          }}
        />
      </Col>
    </Row>
  );
}

Component B:

function UserEmail({ intl, onValueChange }) {
  // Logic based on selectedVoucherOption
  ...
}

Email.propTypes = {
  intl: intlShape.isRequired,
  onValueChange: PropTypes.func.isRequired,
};

The problem I’m facing is figuring out how to pass the selectedVoucherOption state from Component A to Component B (at Line A) in a way that Component B can conditionally render data based on this value.

What’s the best way to achieve this in React?


Solution

  • Rendering a component happens in the JSX, not in a function. (Though a function can certainly be used to build JSX, but that function would have to build JSX and not simply reference a component function like you're attempting.)

    For example:

    <Dropdown
      options={voucherOptions}
      placeholder={intl.formatMessage({ ...messages.voucherOptions.placeholder })}
      onChange={(_evt, obj) => {
        setSelectedOption(obj);
      }}
    />
    <UserEmail />
    

    Note the <UserEmail /> as a standalone element in the markup. You can conditionally include it by wrapping it in a conditional expression. For example:

    <Dropdown
      options={voucherOptions}
      placeholder={intl.formatMessage({ ...messages.voucherOptions.placeholder })}
      onChange={(_evt, obj) => {
        setSelectedOption(obj);
      }}
    />
    { someCondition ? <UserEmail /> : null }
    

    Note that the JavaScript expression is wrapped in {} to indicate that it is an expression and not JSX markup. Whatever condition you use as someCondition would determine whether the expression evaluates to <UserEmail /> or null.

    If you want to pass a prop to it, you'd do that exactly like the props you're already passing to other components:

    <Dropdown
      options={voucherOptions}
      placeholder={intl.formatMessage({ ...messages.voucherOptions.placeholder })}
      onChange={(_evt, obj) => {
        setSelectedOption(obj);
      }}
    />
    { someCondition ? <UserEmail someProp={selectedVoucherOption} /> : null }
    

    And in the component you'd read that prop:

    function UserEmail({ intl, onValueChange, someProp }) {
      // Logic based on someProp
    }
    

    Basically, the component you write is structurally no different from the 3rd party components you're already using. A component is a component either way. You'd include it in the JSX, conditionally or otherwise, and pass props to it like any other component.