Skip to content

Instantly share code, notes, and snippets.

@imranismail
Last active May 8, 2017 04:55
Show Gist options
  • Save imranismail/36c9d10b8206812fae5a4b79afdd1466 to your computer and use it in GitHub Desktop.
Save imranismail/36c9d10b8206812fae5a4b79afdd1466 to your computer and use it in GitHub Desktop.
React with Phoenix

Using React with Phoenix

Create a component renderer helper and pass props as [data-props=""]

defmodule Web.ComponentHelpers do
  import Phoenix.HTML.Tag, only: [content_tag: 3]

  def component(name, props \\ %{})
  def component(name, props) when is_list(props),
    do: component(name, Enum.into(props, %{}))
  def component(name, props),
    do: content_tag(:div, "", data: [component: name, props: Poison.encode!(props)])
end

Create an auto-mount script

import React from './stdlib'
import ReactDOM from 'react-dom'

// Import react component
import CategoryTree from './category-tree'

class App {
  constructor() {
    // Register as part of global.App.Components
    this.Components = {
      CategoryTree
    }

    this.initialize()
  }
  
  // Create an event listener on page load to auto-mount for each div[data-component="<Component>"]
  initialize() {
    $(document).on('turbolinks:load', () => {
      $('[data-component]').each((index, node) => {
        const target = $(node)
        const props = target.data('props')
        const componentName = target.data('component')
        const Component = this.Components[componentName]

        if (Component) {
          ReactDOM.render(<Component {...props} />, node)
        } else {
          throw `Couldn't find component ${componentName} in App.Components`
        }
      })
    })
  }
}

In View

= form_for @changeset, @action, fn f ->
  .field
    .control
      # Create the div[data-component="CategoryTree" data-props="{\"name\": \"resource[category_tree][]\", \"placeholder\": \"Product category\"}"] using the helper so that autocmount script can detect the component and mount it
      = component "CategoryTree", name: f.name <> "[category_tree][]", placeholder: "Product category"
  .field
    .control
      = text_input f, :name, class: "input", placeholder: "Product name"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment