Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 33 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
[![Build Status](https://travis-ci.org/geolessel/react-phoenix.svg?branch=master)](https://travis-ci.org/geolessel/react-phoenix)
[![Hex.pm](https://img.shields.io/hexpm/v/react_phoenix.svg)](https://hex.pm/packages/react_phoenix)

Functions to make rendering React.js components easy in Phoenix.
Functions to make rendering React.js components easy in Phoenix—now
with LiveView support!

Combined with the javascript also included in this package, rendering React
components in your Phoenix views is now much easier. Using the Phoenix default
Expand Down Expand Up @@ -32,7 +33,7 @@ dependencies in `mix.exs`:
```elixir
def deps do
[
{:react_phoenix, "~> 1.2"}
{:react_phoenix, "~> 1.3.0-rc.1"}
]
end
```
Expand Down Expand Up @@ -146,6 +147,26 @@ following line:
import "react-phoenix"
```

#### If you are using LiveView

If you are rendering React components in LiveView, you need to take the
extra step of setting up the LiveView JS hooks. Thankfully, this does
not take much.

In your main application javascript file (usually `assets/js/app.js`), add
(or modify) the following:

```javascript
import ReactPhoenix from "react-phoenix"

// Define a `hooks` variable to keep all our defined LiveView hooks:
let hooks = { ReactPhoenix }

// Use the original LiveSocket constructor, but pass in our hooks
// param ----------------------------------- here -> | <- here
let liveSocket = new LiveSocket("/live", Socket, { hooks, params: { _csrf_token: csrfToken } })
```

### 5. (optional) Import the module into your views for less typing

If you'd like to just call `react_component(...)` in your views instead of the full
Expand Down Expand Up @@ -205,6 +226,14 @@ Once installed, you can use `react_component` in your views by:
javascript helper as a div that should be turned into a React component. It will then render the
named component in that `div` (or a different element specified by ID via the `target_id` option).

3. If you are using LiveView, there will be some extra props passed into
your component that you can utilize: `handleEvent` and `pushEvent`.

- Using `handleEvent`, you can respond to events from the server
- Using `pushEvent`, you can push events to the server

Full information about these functions are available in the [LiveView documentation](https://hexdocs.pm/phoenix_live_view/0.14.8/js-interop.html#client-hooks)


## What about server-side rendering?

Expand All @@ -215,5 +244,7 @@ I couldn't quite get this working with Brunch, but I hope to have time to look a

This package is heavily inspired by the [react-rails](https://github.com/reactjs/react-rails) project.

The LiveView implementation drew inspiration from [phoenix_live_react](https://github.com/fidr/phoenix_live_react).

For more detailed documentation, check out the hex docs at
[https://hexdocs.pm/react_phoenix](https://hexdocs.pm/react_phoenix)
22 changes: 19 additions & 3 deletions lib/react_phoenix/client_side.ex
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ defmodule ReactPhoenix.ClientSide do

The resulting `<div>` tag is formatted specifically for the included javascript
helper to then turn into your named React component and then pass in the props specified.

Since a unique `id` is required for LiveView to track its state, a random numeric
id is assigned.
"""
@spec react_component(name :: String.t(), props :: list | map) :: Phoenix.HTML.safe()
def react_component(name, props) when is_list(props) do
Expand All @@ -51,7 +54,13 @@ defmodule ReactPhoenix.ClientSide do

def react_component(name, props) when is_map(props) do
props = Jason.encode!(props)
content_tag(:div, "", [{:data, [react_class: name, react_props: props]}])

content_tag(:div, "", [
{:data, [react_class: name, react_props: props]},
id: :rand.uniform_real(),
phx_hook: "ReactPhoenix",
phx_update: "ignore"
])
end

@doc """
Expand All @@ -77,6 +86,9 @@ defmodule ReactPhoenix.ClientSide do
The resulting `<div>` tag is formatted specifically for the included javascript
helper to then turn into your named React component and then pass in the props specified.

Since a unique `id` is required for LiveView to track its state, a random numeric
id is assigned.

## Options

You can pass a Keyword list of options that controls the rendering of the final html element
Expand All @@ -98,16 +110,20 @@ defmodule ReactPhoenix.ClientSide do
Phoenix.HTML.safe()
def react_component(name, props, opts) when is_map(props) do
props = Jason.encode!(props)
id = :rand.uniform_real()

{html_element, opts} = Keyword.pop(opts, :html_element, :div)
{target_id, opts} = Keyword.pop(opts, :target_id, "")
{target_id, opts} = Keyword.pop(opts, :target_id, id)

content_tag(
html_element,
"",
Keyword.merge(
[
{:data, [react_class: name, react_props: props, react_target_id: target_id]}
{:data, [react_class: name, react_props: props, react_target_id: target_id]},
id: id,
phx_hook: "ReactPhoenix",
phx_update: "ignore"
],
opts
)
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule ReactPhoenix.Mixfile do
use Mix.Project

@version "1.2.0"
@version "1.3.0-rc.1"
@source_url "https://github.com/geolessel/react-phoenix"

def project do
Expand Down
22 changes: 11 additions & 11 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
%{
"dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm"},
"earmark": {:hex, :earmark, "1.3.1", "73812f447f7a42358d3ba79283cfa3075a7580a3a2ed457616d6517ac3738cb9", [:mix], [], "hexpm"},
"ex_doc": {:hex, :ex_doc, "0.19.2", "6f4081ccd9ed081b6dc0bd5af97a41e87f5554de469e7d76025fba535180565f", [:mix], [{:earmark, "~> 1.2", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
"makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"},
"makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"},
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"},
"phoenix_html": {:hex, :phoenix_html, "2.13.0", "3bad10de5efb6c590f7aa5b316ad0d3faa054715414c9b562c410de4ffb885c5", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm"},
"plug": {:hex, :plug, "1.7.1", "8516d565fb84a6a8b2ca722e74e2cd25ca0fc9d64f364ec9dbec09d33eb78ccd", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"},
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"},
"dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm", "6c32a70ed5d452c6650916555b1f96c79af5fc4bf286997f8b15f213de786f73"},
"earmark": {:hex, :earmark, "1.3.1", "73812f447f7a42358d3ba79283cfa3075a7580a3a2ed457616d6517ac3738cb9", [:mix], [], "hexpm", "000aaeff08919e95e7aea13e4af7b2b9734577b3e6a7c50ee31ee88cab6ec4fb"},
"ex_doc": {:hex, :ex_doc, "0.19.2", "6f4081ccd9ed081b6dc0bd5af97a41e87f5554de469e7d76025fba535180565f", [:mix], [{:earmark, "~> 1.2", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "4eae888633d2937e0a8839ae6002536d459c22976743c9dc98dd05941a06c016"},
"jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fdf843bca858203ae1de16da2ee206f53416bbda5dc8c9e78f43243de4bc3afe"},
"makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "5fbc8e549aa9afeea2847c0769e3970537ed302f93a23ac612602e805d9d1e7f"},
"makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "adf0218695e22caeda2820eaba703fa46c91820d53813a2223413da3ef4ba515"},
"mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm", "6cbe761d6a0ca5a31a0931bf4c63204bceb64538e664a8ecf784a9a6f3b875f1"},
"nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm", "5c040b8469c1ff1b10093d3186e2e10dbe483cd73d79ec017993fb3985b8a9b3"},
"phoenix_html": {:hex, :phoenix_html, "2.13.0", "3bad10de5efb6c590f7aa5b316ad0d3faa054715414c9b562c410de4ffb885c5", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "6bce79ae6987822c288f7653d89c971fef276d1a6977757d6f61e4984b88dc5a"},
"plug": {:hex, :plug, "1.7.1", "8516d565fb84a6a8b2ca722e74e2cd25ca0fc9d64f364ec9dbec09d33eb78ccd", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm", "daa5fee4209c12c3c48b05a96cf88c320b627c9575f987554dcdc1fdcdf2c15e"},
"plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm", "73c1682f0e414cfb5d9b95c8e8cd6ffcfdae699e3b05e1db744e58b7be857759"},
}
Loading