javascripthtmlreactjshtml-generation

How can I generate HTML by function and render it later in JS React


I'm strugling with generating periodic table in HTML from information given in this.periodicTable[] and rendering it later, as you can see in code below. How can I make it work? Firstly i have made it by hand (all in render() section written in HTML), but later I found out that generating it would be better idea. Everything worked until i switched to generating html istead of writting it. I also would like to use periodicTable data in other parts of website so this one is necessary

importing React stuff

class PeriodicTable extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            show: true,
        };
        this.periodicTable = [
            //    1 row
            this.hydrogen = {
                blank: false,
                name: "hydrogen",
                short: "H",
                z: 1,
                mass: 1.006,
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank:true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.blank = {
                blank: true
            },
            this.hellium = {
                blank: false,
                name: "hellium",
                short: "He",
                z: 2,
                mass: 4.0026,
            },
            //    2 row
        ]
        this.output = "";
    }

    generatePeriodicTable = () =>{
        for(let i = 0; i < this.periodicTable.length; i++){
            if(this.periodicTable[i].blank){
                this.output += <div class = "periodicCard" class="blank"></div>;
            }else{
                this.output +=
                <div class="periodicCard">
                    <sup class="periodicZ">{this.periodicTable[i].z}</sup>
                    <div class='center'>
                        <strong class="periodicElement">{this.periodicTable[i].short}</strong>
                    </div>
                    <div class='center'>
                        <p class="periodicMass">{this.periodicTable[i].mass}</p>  
                     </div>
                </div>;
            }
        }
        return this.output;
    }

    showLearnItPage = () =>{
        this.setState({show: false});
    }

    render(){
        if(this.state.show){
            return(
                <div>
                    <h2>Periodic<sup class="sup">table</sup></h2>
                    <main class="biggrid">
                        {this.generatePeriodicTable}{this.output}
                    </main>
                    <div class='center'>
                        <button class='periodic-table-page-button' onClick={this.showLearnItPage}>Back</button>
                    </div>
                </div>
            );
        }else{
           return( <LearnItPage /> );
        }
    }
}

export default PeriodicTable;```


Solution

  • Ok, so I fixed your code and I'll comment all that I did.

    // periodicTable doesn't need to be part of the PeriodicTable Component, Juan Marco has made a good sugestion to stract it to a JSON
    // for now I'll just put it in a variable outside PeriodicTable
    const periodicTable = [
      //    1 row
      {
          blank: false,
          name: "hydrogen",
          short: "H",
          z: 1,
          mass: 1.006,
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank:true
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank: true
      },
      {
          blank: false,
          name: "hellium",
          short: "He",
          z: 2,
          mass: 4.0026,
      },
      //    2 row
    ];
    
    // I've created a new Component that will handle the elements rendering, it's just a Function Component
    function TableElement(props) {
      const { elementData } = props;
      const { blank, z, short, mass } = elementData;
    
      if (blank) return <div className="periodicCard blank" />; // take note that in JSX files, HTML classes are className
    
      return (
        <div className="periodicCard">
            <sup className="periodicZ">{z}</sup>
            <div className='center'>
                <strong className="periodicElement">{short}</strong>
            </div>
            <div className='center'>
                <p className="periodicMass">{mass}</p>  
            </div>
        </div>
      );
    }
    
    class PeriodicTable extends React.Component {
        constructor(props) {
            super(props);
    
            this.state = {
                show: true,
            };
        }
    
        // React knows how to handle arrays of ReactComponents, but you must put a key in each element of the array
        generatePeriodicTable = () => {
          return periodicTable.map((el, i) => <TableElement elementData={el} key={i} />);
        }
    
        showLearnItPage = () => {
            this.setState({ show: false });
        }
    
        render() {
            if(this.state.show) {
                return (
                    <div>
                        <h2>Periodic<sup className="sup">table</sup></h2>
                        <main className="biggrid">
                            {this.generatePeriodicTable()}
                        </main>
                        <div className='center'>
                            <button className='periodic-table-page-button' onClick={this.showLearnItPage}>Back</button>
                        </div>
                    </div>
                );
            }
            // after an if with a return you don't need to use else
            return <LearnItPage />;
        }
    }
    
    export default PeriodicTable;
    

    Now everything should work as you intended. Take some time to read the React Tutorial.