Slide 1

Slide 1 text

Phoenix LiveReact

Slide 2

Slide 2 text

.。oO(さっちゃんですよヾ(〃l _ l)ノ゙ ☆)

Slide 3

Slide 3 text

Phoenix LiveView https://github.com/phoenixframework/phoenix_live_view

Slide 4

Slide 4 text

Phoenix LiveView: Interactive, Real-Time Apps. No Need to Write JavaScript. https://dockyard.com/blog/2018/12/12/phoenix-liveview- interactive-real-time-apps-no-need-to-write-javascript

Slide 5

Slide 5 text

_⼈⼈⼈⼈⼈⼈⼈⼈⼈⼈⼈⼈⼈⼈⼈⼈_ > No Need to Write JavaScript. <  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y ̄

Slide 6

Slide 6 text

Write Elixir. defmodule ExampleWeb.CounterLive do use Phoenix.LiveView def render(assigns) do ~L""" Count: <%= @count %> """ end def mount(%{}, socket) do if connected?(socket), do: :timer.send_interval(1000, self(), :count_up) {:ok, assign(socket, :count, 0)} end def handle_info(:count_up, socket) do count = socket.assigns.count {:noreply, assign(socket, :count, count + 1)} end end

Slide 7

Slide 7 text

Write EEx. <%= Phoenix.LiveView.live_render(@conn, ExampleWeb.CounterLive, session: %{}) %> Done!

Slide 8

Slide 8 text

No Need to Write JavaScript?

Slide 9

Slide 9 text

Taking the principle of excluded middle from the mathematician would be the same, say, as proscribing the telescope to the astronomer or to the boxer the use of his fists. Hilbert (1927)

Slide 10

Slide 10 text

Taking the JavaScript from the Web UI would be the same, say, as proscribing the principle of excluded middle from the mathematician.

Slide 11

Slide 11 text

UI and the changes of UI are difficult. We can't escape from JavaScript.

Slide 12

Slide 12 text

If there is a useChannel React hook…

Slide 13

Slide 13 text

Improving UX with Phoenix Channels & React Hooks – Flatiron Labs – Medium https://medium.com/flatiron-labs/improving-ux-with- phoenix-channels-react-hooks-8e661d3a771e

Slide 14

Slide 14 text

defmodule ExampleWeb.RoomChannel do use ExampleWeb, :channel def join("room:lobby", payload, socket) do socket = assign(socket, :count, 0) :timer.send_interval(1000, self(), :count_up) {:ok, socket} end def handle_info(:count_up, socket) do count = socket.assigns.count + 1 socket = assign(socket, :count, count) push(socket, "count_up", %{count: count}) {:noreply, socket} end end

Slide 15

Slide 15 text

import React from "react"; import ReactDOM from "react-dom"; export default function main() { ReactDOM.render( , document.getElementById("app") ); }

Slide 16

Slide 16 text

import { Socket } from "phoenix"; import { createContext, useEffect } from "react"; const SocketContext = createContext(); function SocketProvider({ wsUrl, options, children }) { const socket = new Socket(wsUrl, { params: options }); useEffect(() => { socket.connect(); }, [options, wsUrl]); return ( {children} ); } SocketProvider.defaultProps = { options: {} };

Slide 17

Slide 17 text

import { useContext, useEffect, useReducer } from "react"; function useChannel(channelTopic, reducer, initialState) { const socket = useContext(SocketContext); const [state, dispatch] = useReducer(reducer, initialState); useEffect(() => { const channel = socket.channel(channelTopic, {}); channel.onMessage = (event, payload) => { dispatch({ event, payload }); return payload; }; channel.join(); return () => { channel.leave(); }; }, [channelTopic]); return state; }

Slide 18

Slide 18 text

function appReducer(state, { event, payload }) { switch (event) { case "count_up": return { ...state, count: payload.count }; default: return state; } } function App(props) { const initialState = { count: 0 }; const { count } = useChannel("room:lobby", appReducer, initialState); return
Count: {count}
; } Done!

Slide 19

Slide 19 text

use-phoenix-channel - npm https://www.npmjs.com/package/use-phoenix-channel