0

I need to dynamically build a React component based on consistently structured text in an unknown order. How do I replace the placeholder numbers (identified in some consistent way, see below) with corresponding components that consume the placeholder as props?

const text = "some (1) arbitrary amount of [2] text";

return (
  <div>
    some
    <Component1 var={1} />
    arbitrary amount of 
    <Component2 var={2} />
    text
   </div>
)

The placement and order of [] and () is not consistent, so that:

const text = "[2] some arbitrary amount (1) of text";

return (
  <div>
    <Component2 var={2} />
    some arbitrary amount
    <Component1 var={1} />
    of text
   </div>
)

3 Answers 3

1

Its a bit tricky, to simplify we replace only one placeholder (1):

const App = () => {
  return <div>{splitAndRender(text, `(1)`, Component1)}</div>;
};

Where splitAndRender can be implemented like:

const splitAndRender = (text, regex, Component) => {
  const splitByRegex = text.split(regex);
  return splitByRegex.reduce((acc, curr, index) => {
    const isLastItem = index === splitByRegex.length - 1;
    return [...acc, curr, isLastItem ? null : <Component key={index} />];
  }, []);
};

For an unknown number of placeholders, it should be done by resursing the returned array from splitAndRender, looking for strings, and calling splitAndRender on such strings.

Edit mystifying-thompson-j9e2m

Sign up to request clarification or add additional context in comments.

4 Comments

Working on implementing this... I don't see how to pass props to Component1? (Maybe I didn't specify this)...
Call the JSX syntax inside the function, and its not related to the question
Updated question to reflect. Sorry to move the goalpost.
You see in the answer how I pass the key prop... Just pass the props in the function, everything you need is included in the answer.
1

Yes possible, you could do something like this

  const C1 = () => " C1 ";
  const C2 = () => " C2 ";
  const dynamics = { // the ids of these dynamic components that will be used as placeholders
    1: C1,
    2: C2
  };
  const text = "some (1) arbitrary amount of [2] text";
   // you may want to customize this function to suit your needs
  const isDynamic = src => {
    return (
      (src[0] === "(" && src[src.length - 1] === ")") ||
      ("[" && src[src.length - 1] === "]")
    );
  };
  const components = text.split(" ");

// dont forget to add a key to the mapped components, but i will leave this to you, since i dont have all the requirements about the dynamic components, and whether there might be duplicates
  return (
    <div >
      {components.map(comp => {

        if (isDynamic(comp)) {
          const dynamicCompId = parseInt(
            comp
              .split("")
              .filter(x => !Number.isNaN(+x))
              .join("")
          );
          const Dynamic = dynamics[dynamicCompId];
          return <Dynamic   />;
        }
        return comp;
      })}
    </div>
  );

Comments

0

I came up with this method which is straightforward and efficient, and saves from having to do nested / iterative loops as the number of needles becomes larger:

// Function to split string on multiple needles, keeping needles in place
function splitMulti(str, needles) {
  let out = str.valueOf()
  for (var i = 0; i < needles.length; i++) {
    out = out.replace(needles[i], `SPLITDELIN${needles[i]}SPLITDELIN`);
  }
  out = out.split('SPLITDELIN');
  return out;
}


function buildChildren(string){
  // string = "some (1) arbitrary amount of [2] text";

  
  const needles = [
    "(1)",
    "[2]",
  ];

  const childArray = splitMulti(string, needles);

  childArray.forEach((item, index, array) => {
    switch (item) {
      case "(1)":
        array[index] = <Component1 var={1} />
        break;
      case [2]:
        array[index] = <Component2 var={2} />
        break;
    }
  });

  return childArray;
};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.