Search code examples
reactjsreact-rails

Can't pass props to IIFE in JSX


I'm trying to use react-rails to create a UI for an existing rails app. I want to make a dynamic todo list which is populated with data from my rails backend. I'm passing the tasks to the component through an erb tag provided by the gem 'react-rails'. This should make the data available as a prop for me to use, but when I try to render it in the JSX, I get an

 Uncaught TypeError: Cannot read property 'tasks' of undefined

error message in the console for the line

 for (var i = 0; i < this.props.tasks.length; i++) {

Here's my code:

The React(rails) component

class TodoApp extends React.Component{

  render() {
    return (
      <div className="card col-6">
        <div className="card-header">
          <div className="float-rights">
            create new button
         </div>
        </div>
       <div className="card-body">
          {
            (function(){
              var html;
             for (var i = 0; i < this.props.tasks.length; i++) {
                html += this.props.tasks[i]
              }
             return html;
            })()
         }
        </div>
     </div>
    )
  }
 }

The ERB/HTML view it's rendered in

 <%= react_component('TodoApp', tasks: @collaboration.tasks) %>

Ideally the loop would run and I would get some output.


Solution

  • You could get your IIFE working by binding this from the outer scope,

    <div className="card-body">
        {
            (function(){
                 var html;
                 for (var i = 0; i < this.props.tasks.length; i++) {
                    html += this.props.tasks[i]
                  }
                return html;
             }).bind(this)()
         }
    </div>
    

    But this is not idiomatic React. The following is,

    <div className="card-body">
        {this.props.tasks.join('')}
    </div>
    

    If the tasks are in html format as indicated by the name of the variable you have used,

    <div className="card-body"
         dangerouslySetInnerHTML={ { __html: this.props.tasks.join('') } }>
    </div>
    

    With this approach you have to sanitize the tasks to prevent script injection and you also lose the benefits of react such as event binding. It is not recommended