Question

Use JSX to create a function to return a value instead of a component

I have this JSX.

  const experiment = () => (
    <Experiment
      experimentName=experiment-abc"
      defaultVariant="control"
    >
      <Variant variant="control">
        <ReturnThisComponentForControl /> // will either return this 
      </Variant>
      <Variant variant="variant">
        <ReturnThisComponentForVariant /> // or return this
      </Variant>
    </Experiment>
  );

I do not own the components Experiment and Variant and can't modify them.

Is there a way I can turn this into a function that returns a value, not a component.

Essentially looking to achieve this.

const getName = () => {
    // logic using the above components to see which block I enter, 
    // `ReturnThisComponentForControl` or `ReturnThisComponentForVariant`
    if (ReturnThisComponentForVariant) return 'variant';
    return 'control'
}
 3  34  3
1 Jan 1970

Solution

 0

Mmm it is difficult to access the variant if the component Experiment or Variant doesn't provide an API to access the variant and differentiate between them

My piece of advice here is that you can take advantage of useEffect because useEffect runs after render on the screen, so probably as a side effect (in the effect) you can get something particular in the variant (DOM/HTML) with web api (like document.querySelector) get which one was rendered, and with the use of hooks return the value that you need for example

// First Approach

const useVariant = () => {
  const [variant, setVariant] = useState("control");
  useEffect(() => {
    // Here get the element with a unique thing that you can get from the variant in the DOM/HTML
    // The empty querySelector is only an example to show you that you need to access DOM and try to find the element
    // IMPORTANT: This only will work if the logic renders only one variant at a time
    const variantElement = document.querySelector();
    if (variantElement) {
      setVariant("variant");
    } else {
      setVariant("control");
    }
  }, []);

  return variant;
};

// Then in the component that renders the experiment

const ComponentThatRendersExperiment = () => {
  // here you will have access to the variant if it was found in the DOM
  const variant = useVariant();
  return (
    <Experiment experimentName="experiment-abc" defaultVariant="control">
      <Variant variant="control">
        <ReturnThisComponentForControl />
      </Variant>
      <Variant variant="variant">
        <ReturnThisComponentForVariant />
      </Variant>
    </Experiment>
  );
};

Or you can try to modify your components and tell the parent via props that one of them was rendered something like this

// Second approach

// You can pass a prop and then the variant is rendered set the state telling the parent which one was rendered example
// IMPORTANT: This only will work if the logic renders only one variant at a time

const ReturnThisComponentForControl = (props) => {
  useEffect(() => {
    props.setVariant("control");
  }, []);

  /* here return the jsx of your current component*/
  return;
};

const ReturnThisComponentForVariant = (props) => {
  useEffect(() => {
    props.setVariant("variant");
  }, []);

  /* here return the jsx of your current component*/
  return;
};

const ComponentThatRendersExperiment = () => {
  // here you will have access to the variant if it was sucessfully mounted in DOM
  const [variant, setVariant] = useState("control");
  return (
    <Experiment experimentName="experiment-abc" defaultVariant="control">
      <Variant variant="control">
        <ReturnThisComponentForControl setVariant={setVariant} />
      </Variant>
      <Variant variant="variant">
        <ReturnThisComponentForVariant setVariant={setVariant} />
      </Variant>
    </Experiment>
  );
};

2024-07-09
Yuu