dev404
dev404

Reputation: 1098

How do you render HTML tags in React with Coffeescript?

I'm currently learning ReactJS and how to work with Ruby on Rails as its backend, so I apologize if I'm making dumb assumptions, feel free to scold me.

I'm following a tutorial where the author is using Coffeescript instead of ES6 to handle his ReactJS code.

He provides an example component similar to this (coffeescript):

@Rows = React.createClass
  render ->
    React.DOM.div
      className: 'rows'
      React.DOM.h1
        className: 'title'
        'Rows'

This has two errors. The first one pertains to React.createClass which I found out has been deprecated and no longer works. Instead I'm using createReactClass. Good. But now, React.DOM.h1 gives an error saying Uncaught TypeError: Cannot read property 'h1' of undefined, same for whichever other HTML tag I use. I assume it's due to createReactClass not providing the necessary functionality previously provided by React.createClass.

Anyway, while researching for another error indirectly related to this, I found someone suggesting to use something like this:

@Rows = React.createClass
  render ->
    div
      className: 'rows'
      h1
        className: 'title'
        'Rows'

So, cutting off the React.DOM part. This gives another type of error, saying: Uncaught ReferenceError: div is not defined. Again, I'm assuming it's due to the change to React.createClass.

Is there a way to use React with CoffeeScript, such that I could use it like this:

@Rows = createReactClass
  render ->
    div
      className: 'rows'
      h1
        className: 'title'
        'Rows'

without having to open and close HTML tags, and without React.DOM?

I don't know if it's possible at all, or if it ever worked, or even if there're many ways to achieve something with similar results. I'm just curious to know if there's a way to do it like this before I dive deeper onto React.

Thanks!

Update

I've made some progress, though I'm still getting an error. I tried the following:

import React from 'react'
import ReactDom from 'react-dom'
{div, h1, p} = ReactDom

class Rows extends React.Component
  render: ->
    h1
      className: 'col-md-12'
      'Rows'
  
export default Rows

This gives the following error: Uncaught TypeError: h1 is not a function.

Upvotes: 2

Views: 2483

Answers (2)

dev404
dev404

Reputation: 1098

Here's what finally worked

React = require('react')
PropTypes = require('prop-types')
ReactDom = require('react-dom-factories')
createReactClass = require('create-react-class')
{div, h1} = ReactDom

Rows = createReactClass
  render: ->
    div
      className: 'col-md-12'
      h1
        className: 'title'
        'Rows'

export default Rows

So I've been using React 16 and it's incredible how many things have changed in the last 6 months. I'm TOTALLY new to React, so I had absolutely no idea how this worked, but I managed to use the code above without errors.

First:

ReactDom = require('react-dom-factories')

This is the one I was missing. I was getting errors that div and h1 weren't functions, or weren't defined. So it turns out that per the documentation React.DOM is now available as react-dom-factories:

The deprecations introduced in 15.x have been removed from the core package. React.createClass is now available as create-react-class, React.PropTypes as prop-types, React.DOM as react-dom-factories, react-addons-test-utils as react-dom/test-utils, and shallow renderer as react-test-renderer/shallow.

Second:

If anyone else runs onto this and you get errors that say Cannot find module "react-dom-factories", it means you have to add them to your webpacker with this:

yarn add react-dom-factories

You may also have to add create-react-class and prop-types, if you're following my example above.

Lastly:

Be sure the extension of your coffeescript file is simply .coffee. If you use .js.coffee or .jsx.coffee you'll get errors that the component cannot be found.

I'm not 100% sure if this is necessary, but I also added cjsx-loader to my webpacker when I was searching for a solution. It's a coffee-react-transform loader module for Webpack.

UPDATE: This last part wasn't necessary. I made a new project and this wasn't required at all.

Upvotes: 3

caffeinated.tech
caffeinated.tech

Reputation: 6548

You can use coffeescript with React without JSX. I think it makes for much cleaner code:

React = require('react')
ReactDOM = require('react-dom')
{div, h1} = ReactDom


class Rows extends React.Component

  render: ->
    div
      className: 'rows'
      h1
        className: 'title'
        'Rows'

module.exports = React.createFactory Rows
  1. Depending on the version of React you are using, you may need to separately include the React-DOM package
  2. Destructure ReacDom to use the DOM elements directly
  3. Use the class syntax of Coffeescript instead of the legacy functions.
  4. Export a factory of your component so you can easily use it in another component:

 Rows = require('./rows')

 class OtherComponent extends React.Component
   .
   .
   .
   render: ->
     div
       className: 'container'
       Rows()

Upvotes: 3

Related Questions