React rendering variable with html characters escaped

17,304

React actually has a page that addresses this and some other potential solutions (using unicode characters, saving the file as utf8, using dangerouslySetInnerHtml): jsx-gotchas


Another option is to create a simple, reusable Temp component that has types you pass it:

const TEMP_C = 'C';
const TEMP_K = 'K';

const Temp = ({ children, unit }) => <span>{children}&deg;{unit}</span>;

const App = () => (
  <div>
    <p>Temperature 1: <Temp unit={TEMP_K}>25</Temp></p>
    <p>Temperature 2: <Temp unit={TEMP_C}>25</Temp></p>
  </div>
);

ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Share:
17,304
Judd Franklin
Author by

Judd Franklin

Make and maintain websites for companies and organizations with a special focus on nonprofits. We focus on making Wordpress sites that give users and admins mutually pleasurable user experiences. I personally really enjoy JavaScript development.

Updated on June 05, 2022

Comments

  • Judd Franklin
    Judd Franklin almost 2 years

    I am learning React and have run into the following situation:

    I have a string variable that I am passing as a prop to different components to be rendered by JSX.

    When the component and its sub-components are rendered, the string does not render html special characters, instead rendering the character code as text.

    How can I get the variable to render as html?

    Here is the code for a component that works completely, except that the tempUnitString variable renders as &deg; K, while the <th> below renders its units as ° K.

    import React, { Component } from 'react';
    import { connect } from 'react-redux';
    import Chart from '../components/chart';
    import GoogleMap from '../components/google_map'
    
    class WeatherList extends Component {
      renderWeather(cityData, tempUnits){
        const name = cityData.city.name;
        const id = cityData.city.id;
        const humidity = cityData.list.map(weather => weather.main.humidity);
        const pressure = cityData.list.map(weather => weather.main.pressure);
        const { lon, lat } = cityData.city.coord;
        let temp = cityData.list.map(weather => weather.main.temp);
        if (tempUnits === "K"){
            temp = cityData.list.map(weather => weather.main.temp);
        } else if (tempUnits === "F"){
            temp = cityData.list.map(weather => weather.main.temp * 9/5 - 459.67);
        } else {
            temp = cityData.list.map(weather => weather.main.temp - 273.15);
        }
        let tempUnitString = "&deg; " + tempUnits;
    
        return (
          <tr key={ id }>
            <td><GoogleMap lat={ lat } lon={ lon } /></td>
            <td>
              <Chart color="red" data={ temp } units={ tempUnitString } />
            </td>
            <td>
              <Chart color="green" data={ pressure } units=" hPa" />
            </td>
            <td>
              <Chart color="orange" data={ humidity } units="%" />
            </td>
          </tr>);
      }
      render() {
        const tempUnits = this.props.preferences.length > 0 ? this.props.preferences[0].tempUnits : "K";
    
        return (
          <table className="table table-hover">
            <thead>
              <tr>
                <th>City</th>
                <th>Temperature (&deg; { tempUnits })</th>
                <th>Pressure (hPa)</th>
                <th>Humidity (%)</th>
              </tr>
            </thead>
            <tbody>
              { this.props.weather.map( item => this.renderWeather(item,tempUnits) ) }
            </tbody>
          </table>
        );
      }
    
    
    }
    
    function mapStateToProps({ weather, preferences }){// { weather } is shorthand for passing state and { weather:state.weather } below
      return { weather, preferences }; // === { weather:weather }
    }
    
    export default connect(mapStateToProps)(WeatherList);
    

    UPDATE

    Using the documentation passed to me by @James Ganong I set up a boolean prop on the subcomponent isTemp and based on that created a JSX variable.

    The subcomponent (minus includes and func definitions) looks like this:

    export default (props) => {
      let tempDeg = '';
      if (props.isTemp){
        tempDeg = <span>&deg;</span>;
      }
      return (
        <div>
          <Sparklines height={ 120 } width={ 100 } data={ props.data }>
            <SparklinesLine color={ props.color } />
            <SparklinesReferenceLine type="avg" />
          </Sparklines>
          <div>{ average(props.data)} { tempDeg }{ props.units }</div>
        </div>
      );
    }
    

    The call to it looks like this:

    <Chart color="red" data={ temp } units={ tempUnits } isTemp={ true } />

  • Judd Franklin
    Judd Franklin about 7 years
    Hi Jordan, The problem is that I want to pass the concatenated string into a separate component as a param. I would rather not have to put clunky conditional logic into the subcomponent, or create separate components just to handle this one case.
  • Judd Franklin
    Judd Franklin about 7 years
    I checked out your approach, and the problem appears to be with the way that the string is being passed to the subcomponent
  • Judd Franklin
    Judd Franklin about 7 years
    Perhaps a conversion from string variable to props property changes rendering behavior?
  • Jordan Enev
    Jordan Enev about 7 years
    Here is described what's happening: reactjs.cn/react/docs/jsx-gotchas.html. Thanks to James' answer.
  • Judd Franklin
    Judd Franklin about 7 years
    Thanks for this information. I marked it as the solution because you found documentation that I couldn't. haha. Ultimately, I need to customize this approach and use some conditional logic because I am running the temperature through a generic component that creates sparklines for temperature and other datasets. I'll add my final solution as an additional solution below.
  • Judd Franklin
    Judd Franklin about 7 years
    I wound up just updating the question with the solution.
  • James Ganong
    James Ganong about 7 years
    Cheers - two things: 1. if you need to pass a prop as true (like isTemp={true}) you actually don't need the ={true} part, just by setting isTemp as an attribute (without the equals) it evals to true. 2. You could combine the if statement into the jsx instead of needing to use the tempDeg variable. ie replace { tempDeg } with {props.isTemp && (<span>&deg;</span>)}
  • Judd Franklin
    Judd Franklin about 7 years
    Cheers to that as well!