Home > other >  Show rating stars in react not showing any stars
Show rating stars in react not showing any stars

Time:04-08

I am building website of Mangas where each Manga has star reviews. I am done with backend but since I am very new to react, I can not figure out how to display stars on webpage. I'm developing it in Django so: id="{{ rating }}" is a loop where I display each manga with title, rating and so on. console.log(prop.id) returns each manga rating 2 times so mangas with ratings 2, 4, 5 are logged as 2, 4, 5, 2, 4, 5.

code

{% block script %}
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
{% endblock %}
<script type="text/babel">
    function Apicall(props) {
        props.star.forEach(prop => {
            return Render_rating(prop.id)
        });
        
    
       function Render_rating(props) {
           if (parseInt(Math.round(props) == 0)) {
            return (
                <img src="static/mangas/nostar.png"/>
            )
           }
           else {
           for (var i = 0; i = parseInt(Math.round(props)); i  ) {
           return Render_stars()
        }
       } 
       
       function Render_stars() {
           return (
           <img src="static/mangas/fullstar.png"/>
           )
       }
    }
}
       ReactDOM.render(<Apicall star={document.querySelectorAll(".stars")}  />, document.getElementById('app'))
     </script>
{% for manga, rating in mangas %}
<div id="manga">
<a href="{% url 'manga' manga.id %}">
<div  id="{{ rating }}"></div>
<div id="app"></div>
<h1>{{ manga.title }}</h1>
<img src="{{ manga.image.url }}">
<br/>{% for genre in manga.genre.all %}{{ genre }}<br/>{% endfor %}
{{ manga.Description }}
</a>
</div>
{% endfor %}

error: Nothing was returned from render

CodePudding user response:

I'm making two assumptions. 1) that your data is an array of objects, and 2) that your rating will be "out of five stars"

Have two functions: one to map over the array of objects, and another to create the stars for each object.

const { useState } = React;

function Example({ data }) {

  // Passing in a rating object,
  // create a new array, and then loop
  // pushing stars into the array depending
  // on the rating, and then returning the array
  function getStars(rating) {
    const stars = [];
    for (let i = 0; i < 5; i  ) {
      if (rating - 1 < i) {
        stars.push(<span>☆</span>);
      } else {
        stars.push(<span>★</span>);
      }
    }
    return stars;
  }

  // `map` over the data, and for each object
  // call `getStars`, and return an array of JSX
  // that contains the manga name, and the result of that call
  function getRatings(data) {
    return data.map(obj => {
      return (
        <div>
          <span className="name">{obj.name}</span>
          <span className="stars">{getStars(obj.rating)}</span>
        </div>
      );
    });
  }

  // Then just call `getRatings`
  return (
    <div>
      {getRatings(data)}
    </div>
  );

}

const data = [
  { name: 'Manga1', rating: 1 },
  { name: 'Manga2', rating: 4 },
  { name: 'Manga3', rating: 5 },
  { name: 'Manga4', rating: 0 },
  { name: 'Manga5', rating: 2 },
];

ReactDOM.render(
  <Example data={data} />,
  document.getElementById('react')
);
.name { margin-right: 1em; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

To (mostly) satisfy Cesare's comment here's the same code but as separate components.

const { useState } = React;

function Example({ data }) {

  function getRatings(data) {
    return data.map(obj => {
      return <Rating data={obj} />
    });
  }

  return (
    <div>
      {getRatings(data)}
    </div>
  );

}

function Rating({ data }) {
  return (
    <div>
      <span className="name">{data.name}</span>
      <Stars rating={data.rating} />
    </div>
  );
}

function Stars({ rating }) {
  
  function buildStars(rating) {
    const stars = [];
    for (let i = 0; i < 5; i  ) {
      if (rating - 1 < i) {
        stars.push(<Star type="white" />)
      } else {
        stars.push(<Star type="black" />)
      }
    }
    return stars;
  }
  
  return (
    <span className="stars">
      {buildStars(rating)}
    </span>
  );

}

function Star({ type }) {
  if (type === 'white') return <span>☆</span>
  return <span>★</span>
}

const data = [
  { name: 'Manga1', rating: 1 },
  { name: 'Manga2', rating: 4 },
  { name: 'Manga3', rating: 5 },
  { name: 'Manga4', rating: 0 },
  { name: 'Manga5', rating: 2 },
];

ReactDOM.render(
  <Example data={data} />,
  document.getElementById('react')
);
.name { margin-right: 1em; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>

CodePudding user response:

I think this would be a better approach to this kind of need:

  • You have a score
  • You use the score to generate an array of emoji ( you can use SVG or whatever you prefere )
  • You render the array with JSX

In React it's always better not to mix data manipulation logic and JSX code, JSX code should be the view layer that just renders your data. An example implementation of a Stars Component:

   function Stars({ score }) {
    const stars = useMemo(() => {
    const stars = [];
    for (let i = 1; i <= 5; i  ) {
      stars.push(i <= Math.round(score) ? '★' : '⚝');
    }   
    return stars;
  }, [score]);

  return stars.map((el) => <span>{el}</span>);
}

Every data manipulation operation performed inside a React Component should be memoized with useMemo hook .

Here a working example that you can play with.

  • Related