Dynamically change React Component JSX

66 Views Asked by At

I am trying an experiment to generate a random component. I have a sandbox with a basic example of this idea.

https://codesandbox.io/s/practical-kalam-mz9sdy?file=/src/App.js

For example I have components named like :

const Test0 = () => {
    return (
      <>
        <p> Hello, I am default text</p>
      </>
    );
  };

  const Test1 = () => {
    return (
      <>
        <p>Text String #1</p>
      </>
    );
  };
  const Test2 = () => {
    return (
      <>
        <p>Text String #2</p>
      </>
    );
  };

And a button that will randomly generate which of those components to use by its function name.

const handleClick = (e) => {
    let num = getRandomNumber(1, 5);
    let newString = "Test" + num;

    // without eval it just prints the string, eg: Test1
    // setOutput(newString);
    setOutput(eval(newString));
  };

Using eval works for this but I am sure there is a better way to activate the component. Just passing the function name for the initial state works fine :

  const [output, setOutput] = useState(Test0);

The second test I trying to run the typing function with the dynamic component. You can see it the example it runs fine with the initial value of useState but then when clicking the test I see no errors and I see expected console log but the typing output is not activated in the same way the test components are swapped out.

// The typing component will not work with this method

 const Direction4 = () => {
    return (
      <Typist typingDelay={50} cursor={<span className="cursor">|</span>}>
        This is another amazing dirction description.
      </Typist>
    );
  };

Thanks for any suggestions on how I could render components dynamically this way.

1

There are 1 best solutions below

4
Zac Anger On

No need for strings and eval and all of that, you can put your components in an array and pick one right from there:

const Test1 = () => <p>Text String #1</p>
const Test2 = () => <p>Text String #2</p>
const testComponents = [Test1, Test2]
const handleClick = () => {
  const randomElement = testComponents[
    Math.floor(Math.random() * testComponents.length)
  ]
  setOutput(randomElement)
}

The same logic can be used for the second section:

const directions = [DefaultType, Direction1]
const handleClickTwo = () => {
  const randomElement = directions[
    Math.floor(Math.random() * directions.length)
  ]
  setOutputTwo(randomElement);
};