Home > Software design >  How to convert ReactNode to an array?
How to convert ReactNode to an array?

Time:01-04

I'm trying to create a component where certain HTMLElements or ReactComponents are passed to it like this:

<ContentList>
   <span>Hi</span> // Passed child No. 1
   <span>Hi2</span> // Passed child No. 2
   <CustomComponent prop1={}></CustomComponent> // Passed child No. 3
</ContentList>

Then, it will render the passed children into this structure:

render() {
    let content: React.ReactNode = this.props.children;
    //----------------------
    //Desired Process goes here
    //----------------------
    return (
      <>
        <section className={styles.list}></section>
        <section className={styles.contentPanel}></section>
      </>
    );
}

Where the first section is supposed to be a content list and the second section is going to be the rendered ReactComponents and HTMLElements. My question is How am I supposed to work with props.children (aka content) as an array? I tried to search for it online but there is no solid guide out there. Basically I want to do something like this:

let content: React.ReactNode = this.props.children;

// Creating relevant anchor for each content
let list = content.map((child, i) => {
  return (<a className="content-link" href={"#" child.id}>{child.title}</a>)
});

// Rendering each content after wrapping them inside proper div
let contents = content.map((child, i) => {
  return (<div className="content">{child}</div>)
});

return (
  <>
    <section className={styles.list}>{list}</section>
    <section className={styles.contentPanel}>{contents}</section>
  </>
);

CodePudding user response:

class App(){
  // Creating relevant anchor for each content
  function list(){
    return this.props.children.map((child, i) => {
      return (<a className="content-link" href={"#" child.id}>{child.title} </a>)
    });
  }  

  // Rendering each content after wrapping them inside proper div
  function contents(){
    return this.props.children.map(...)
  }

  render() {
    return (
      <>
        <section className={styles.list}>{list()}</section>
        <section className={styles.contentPanel}>{contents()}</section>
      </>
    )
  }
}

CodePudding user response:

The Typescript compiler is super strict on variable type in declaration and assignment but I managed to get it working by the following process:

render() {
  let content: React.ReactNode = this.props.children;
  let list: Array<JSX.Element> = [], // #1
       contents: Array<JSX.Element> = []; // #1
  if (this.props.children !== undefined && this.props.children !== null) {
    if (Array.isArray(content)) {
      let arr: Array<any> = content; // #2
      list = arr.map((child, i) => {
        return (
          <a
           className={styles.contentAnchor}
           href={"#content_"   child.props.id}
          >
            {child.props.title}
          </a>
        );
      });
      contents = arr.map((child, i) => {
        return (
          <div
            id={"content_"   child.props.id}
            className={styles.contentWrapper}
          >
            {child}
          </div>
        );
      });
    }
  }
  return (
    <>
      <section className={styles.list}>{list}</section>
      <section className={styles.contentPanel}>{contents}</section>
    </>
  );
}

The actual key lines that were missing from the start are the ones I marked with #

  •  Tags:  
  • Related