Output JSX From a Function Called by a React Component?


#1

Is it possible to call a function from inside a React component, that does a repetitive task and outputs jsx?

For example, something like this (although this code does not work):

import React from 'react';

function displayStarRating(starRating){
  var result = '';
  for (var i = 1; i <= starRating; i++){
    result += '<div><img src = "/public/star.jpg"></div>';
  }

  return result;
}

class Reviews extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
        <div>
                {displayStarRating(4)}
        </div>
    );
  }
}

export default Reviews;

#2

Sure is! JSX is “just javascript”, which refers to exactly this kind of idea.


#3

Excellent!

What is the correct syntax? This approach inserts the text of the html into the client’s browser, i.e. <div>===STAR===</div><div>===STAR===</div><div>===STAR===</div> appears as a string in the browser, rather being parsed into elements and inserted into the dom:

import React from 'react';

function displayStarRating(starRating){
  var result = '';
  for (var i = 1; i <= starRating; i++){
    result += '<div>===STAR===</div>';
  }

  return result;
}

class Reviews extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
        <div>
                {displayStarRating(4)}
        </div>
    );
  }
}

export default Reviews;

I also tried this approach:

import React from 'react';

function displayStarRating(starRating){
  var result = '';
  for (var i = 1; i <= starRating; i++){
        <div>===STAR===</div>
  }
}

class Reviews extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
        <div>
                {displayStarRating(4)}
        </div>
    );
  }
}

export default Reviews;

…but the div and its text “===STAR===” do not appear in the resulting html source or in the client browser.


#4
function displayStarRating(starRating){
    return starRating.map((index) => (
      <div key={index}>===STAR===</div>
    ) 
  }
}

class Reviews extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
        <div>
                {displayStarRating(4)}
        </div>
    );
  }
}

Nesting React Components via a Function?
#5

I don’t think you can map an integer. I tried:

function displayStarRating(starRating){
  return starRating.map(index => (
      <div key={index}>===STAR===</div>
  ))
}

…and got the console error:

TypeError: starRating.map is not a function

I also tried adding key={index}:

function displayStarRating(starRating){
  for (var i = 1; i <= starRating; i++){
    <div  key={i}>===STAR===</div>;
  }
}

…but the div and its text “===STAR===” do not yet appear in the resulting html source or in the client browser.


#6

Try this:

function displayStarRating(starRating) {
  var result = [];
  for (var i = 1; i <= starRating; i++) {
    result.push(<div>===STAR===</div>);
  }
  return result;
}

#7

@jeffm, that totally worked. Thanks!


#8

That’s a pretty ugly / non-functional way of doing things. I would just use lodash.range to map over it.

import range from 'lodash/range'

function displayStarRating(starRating){
    return range(starRating).map((index) => (
      <div key={index}>===STAR===</div>
    ) 
  }
}

class Reviews extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
        <div>
                {displayStarRating(4)}
        </div>
    );
  }
}

#9

Thanks for this excellent syntax, @clayne.


#10

Maybe, but this was also the simplest refactor of @vikr00001’s code. The error in that code was that React elements in the JSX code were being treated as template strings, so the only change I made was to correct the data type.

I also remain unconvinced that creating an array for the sole purpose of having something to map over is a better solution. It feels like an imperative solution masquerading as a declarative one to me. I did like the idea of mapping over the integer. That sent me straight to the repl hoping that it was a thing!


#11

It may not be ideal, but IMO it’s much cleaner and less error-prone than writing a for statement.