React Components In Lucky With Laravel Mix and lucky-react
Tags: react, lucky, laravel, crystal
Published: 2018-07-30 15:56:24

---
title: React Components In Lucky With Laravel Mix and lucky-react
published: true
description: In this post I'm going to show you how you can add React components to your Lucky applications with Laravel mix and lucky-react
tags: react, lucky, laravel, crystal
---

I just started learning React after 2 years of Angular, and I'm surprised at how fun React is and how amazing the community and supporting packages are. I'm also a huge fan of [Crystal](https://crystal-lang.org) and the [Lucky framework](http://luckyframework.com), so what could be more awesome than using these tools together?

In this post I'm going to show you how you can add React components to your Lucky applications with Laravel mix and [lucky-react](https://github.com/mikeeus/lucky-react).

## Demo

To see code for this feature you can clone the `lucky_demo` repo and checkout the `lucky-react` branch.

```
git clone git@github.com:mikeeus/lucky_demo.git
cd lucky_demo
bin/setup
git checkout lucky-react
```

Otherwise you can follow along with a fresh lucky app by running `lucky init app_name`.

## Laravel Mix

Since we'll be using jsx to write React components we need to update Laravel mix's config to compile our JavaScript correctly. Laravel mix makes it easy to set it up by changing our `mix.js()` call in the configuration to `mix.react()`.

```javascript
// webpack.mix.js
mix
  // ...
  .react("src/js/app.js", "public/js") // instead of .js(...)
```

## Babel Plugin: transform-class-properties (Optional)

In order to use arrow functions and other awesome syntax we need babel's `transform-class-properties` plugin. Laravel mix does not come with this plugin by default so we need to install it.

`yarn add babel-plugin-transform-class-properties`

Then we add a `.babelrc` file in the root of our project with the following content:

```json
{
  "plugins": [
    "transform-class-properties"
  ]
}
```

This will be picked up by mix automatically! Dope.

## Writing React Components

Now that we have support for jsx, we can write components and import them into our `app.js` file. For organization I put my components in the `src/js/components/` directory.

Here is the `Bordered` component and a simplified version of the `Chat` component that are used in the demo app.

```javascript
// src/js/components/Bordered.jsx
import React from 'react';

export class Bordered extends React.Component {  
  render() {
    return (
      <div style={{border: '2px solid'}}>
        {this.props.children}
      </div>
    )
  }
}
```

```javascript
// src/js/components/Chat.jsx
import React from 'react';

import { ChatInput } from './ChatInput';
import { Message } from './Message';

export class Chat extends React.Component {
  ...
  render() {
    return (
      <div style={styles}>
        <h2 style={styles}>Conversation</h2>
        <div>
          {
            this.state.messages.map(message => 
              <Message
                key={message.id}
                sender={message.sender}
                text={message.text} />
            )
          }
        </div>
        <ChatInput writeMessage={this.onWriteMessage}/>
      </div>
    )
  }
}
```

## LuckyReact

To allow rendering React components in Lucky apps I've created an npm module called [lucky-react](https://github.com/mikeeus/lucky-react) that adds event listeners on `turbolinks:load` and `turbolinks:before-render` to mount and unmount components using `[data-react-class]` and `[data-react-props]` attributes.

I've also created a crystal shard called [lucky_react](https://github.com/mikeeus/lucky_react) with helper methods for rendering elements with these attributes in your Lucky pages.

**lucky-react npm module**: Finds and renders React components on your pages using `[data-react-class]` and `[data-react-props]` attributes.
**lucky_react crystal module**: Adds helper methods for rendering elements with the right attributes so they can be found by `lucky-react`.

Lets use them now to render our `Chat` and `Bordered` components on our home page.

First install the npm module.

```
yarn add lucky-react
```

Then add the shard to `shard.yml` and run `shards`.

```
# shard.yml
...
  dependencies:
    ...
    lucky_react:
      github: mikeeus/lucky_react
```

## Registering React Components

In order for `LuckyReact` to render our components we need to import and register them in our `app.js` file.

```
// src/js/app.js
...
import LuckyReact from "lucky-react";

import { Chat } from './components/Chat';
import { Bordered } from './components/Bordered';

LuckyReact.register({ Chat, Bordered });
```

That's all we need to do! `LuckyReact` will create event listeners on `turbolinks:load` and `turbolinks:before-render` to mount and unmount these components if it finds them on the page.

Note that we only need to register `Chat` and `Bordered` since they are the only root components.`ChatInput` and `Message` are nested within `Chat` and will be handled automatically by React.

## Rendering Components on Pages

Now in our Pages we can use the `LuckyReact` crystal module to add elements which reference our components so they can be rendered.

```ruby
# src/pages/home/index_page.cr
require "lucky_react"

class Home::IndexPage < GuestLayout
  include LuckyReact # include the module

  def content
    react "Bordered" do # call react
      h1 "React Component", style: "text-align: center;"
    end

    messages = [
      { id: 1, sender: "me", text: "Hi" },
      { id: 2, sender: "Chatbot", text: "Hi! How can I help?" },
      { id: 3, sender: "me", text: "Can you tell me the time?" },
      { id: 4, sender: "Chatbot", text: "Sure it's #{Time.now}" }
    ]

    react "Chat", { messages: messages } # with props
  end
end
```

We can render components without the `lucky_react` shard by adding the `[data-react-class]` and `[data-react-props]`. The above example would then be written like this:

```ruby
# src/pages/home/index_page.cr
class Home::IndexPage < GuestLayout
  def content
    div  "data-react-class": "Bordered" do
      h1 "React Component", style: "text-align: center;"
    end

    messages = [
      { id: 1, sender: "me", text: "Hi" },
      { id: 2, sender: "Chatbot", text: "Hi! How can I help?" }
    ]

    div "data-react-class": "Chat", "data-react-props": ({ messages: messages }).to_json
  end
end
```

If you run the app now and visit the home page you'll see the chat component working!

## Join Us

I hope you enjoyed this tutorial and found it useful. Join us on the [Lucky gitter channel](https://gitter.im/luckyframework/Lobby) to stay up to date on the framework or [checkout the docs](https://luckyframework.org/guides) for more information on how to bring your app idea to life with Lucky.