Skip to content
Closed
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
12 changes: 5 additions & 7 deletions assets/js/live_react/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,11 @@ export function getHooks(components) {
}
},
destroyed() {
if (this._root) {
window.addEventListener(
"phx:page-loading-stop",
() => this._root.unmount(),
{ once: true },
);
}
const root = this._root;
if (!root) return;

this._root = null;
root.unmount();
},
};

Expand Down
19 changes: 19 additions & 0 deletions assets/js/live_react/hooks.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ describe("ReactHook", () => {
beforeEach(async () => {
vi.resetModules();
renderMock.mockClear();
rootMock.unmount.mockClear();
({ getHooks } = await import("./hooks"));
({ ReactHook } = getHooks({ TestComponent }));
});
Expand Down Expand Up @@ -219,4 +220,22 @@ describe("ReactHook", () => {

expect(lastRenderedProps().title).toBe("World");
});

it("destroyed() immediately unmounts the root exactly once and clears it", () => {
const hook = createMockLiveViewHook({
"data-name": "TestComponent",
"data-props": encodeProps({ title: "Hello" }),
});

ReactHook.mounted.call(hook);
ReactHook.destroyed.call(hook);

expect(rootMock.unmount).toHaveBeenCalledTimes(1);
expect(hook._root).toBeNull();

window.dispatchEvent(new Event("phx:page-loading-stop"));
ReactHook.destroyed.call(hook);

expect(rootMock.unmount).toHaveBeenCalledTimes(1);
});
});
2 changes: 0 additions & 2 deletions lib/live_react.ex
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ defmodule LiveReact do
alias Phoenix.LiveView
alias Phoenix.LiveView.LiveStream

require Logger

@ssr_default Application.compile_env(:live_react, :ssr, true)
@diff_default Application.compile_env(:live_react, :enable_props_diff, true)

Expand Down
31 changes: 28 additions & 3 deletions lib/live_react/encoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -52,33 +52,44 @@ defprotocol LiveReact.Encoder do
@doc """
Encodes a value to one of the primitive types.
"""
@spec encode(t) :: any()
def encode(value)

@spec encode(t, opts) :: any()
def encode(value, opts \\ [])
def encode(value, opts)
end

defimpl LiveReact.Encoder, for: Integer do
def encode(value), do: encode(value, [])
def encode(value, _opts), do: value
end

defimpl LiveReact.Encoder, for: Float do
def encode(value), do: encode(value, [])
def encode(value, _opts), do: value
end

defimpl LiveReact.Encoder, for: BitString do
def encode(value), do: encode(value, [])
def encode(value, _opts), do: value
end

defimpl LiveReact.Encoder, for: Atom do
def encode(value), do: encode(value, [])
def encode(atom, _opts), do: atom
end

defimpl LiveReact.Encoder, for: List do
def encode(value), do: encode(value, [])

def encode(list, opts) do
Enum.map(list, &LiveReact.Encoder.encode(&1, opts))
end
end

defimpl LiveReact.Encoder, for: Map do
def encode(value), do: encode(value, [])

def encode(map, opts) do
Map.new(map, fn {key, value} ->
{key, LiveReact.Encoder.encode(value, opts)}
Expand All @@ -87,6 +98,8 @@ defimpl LiveReact.Encoder, for: Map do
end

defimpl LiveReact.Encoder, for: [Date, Time, NaiveDateTime, DateTime] do
def encode(value), do: encode(value, [])

def encode(value, _opts) do
@for.to_iso8601(value)
end
Expand All @@ -98,6 +111,8 @@ defimpl LiveReact.Encoder, for: Any do

quote do
defimpl LiveReact.Encoder, for: unquote(module) do
def encode(value), do: encode(value, [])

def encode(struct, opts) do
struct
|> Map.take(unquote(fields))
Expand All @@ -107,6 +122,8 @@ defimpl LiveReact.Encoder, for: Any do
end
end

def encode(value), do: encode(value, [])

def encode(%{__struct__: module} = struct, _opts) do
raise Protocol.UndefinedError,
protocol: @protocol,
Expand Down Expand Up @@ -178,6 +195,8 @@ defimpl LiveReact.Encoder, for: Any do
end

defimpl LiveReact.Encoder, for: Phoenix.LiveView.AsyncResult do
def encode(value), do: encode(value, [])

def encode(%Phoenix.LiveView.AsyncResult{} = struct, opts) do
LiveReact.Encoder.encode(
%{
Expand All @@ -196,6 +215,8 @@ defimpl LiveReact.Encoder, for: Phoenix.LiveView.AsyncResult do
end

defimpl LiveReact.Encoder, for: Phoenix.LiveView.UploadConfig do
def encode(value), do: encode(value, [])

def encode(%Phoenix.LiveView.UploadConfig{} = struct, opts) do
errors =
Enum.map(struct.errors, fn {key, value} ->
Expand Down Expand Up @@ -225,6 +246,8 @@ defimpl LiveReact.Encoder, for: Phoenix.LiveView.UploadConfig do
end

defimpl LiveReact.Encoder, for: Phoenix.LiveView.UploadEntry do
def encode(value), do: encode(value, [])

def encode(%Phoenix.LiveView.UploadEntry{} = struct, opts) do
LiveReact.Encoder.encode(
%{
Expand All @@ -243,6 +266,8 @@ defimpl LiveReact.Encoder, for: Phoenix.LiveView.UploadEntry do
end

defimpl LiveReact.Encoder, for: Phoenix.HTML.Form do
def encode(value), do: encode(value, [])

def encode(%Phoenix.HTML.Form{} = form, opts) do
LiveReact.Encoder.encode(
%{
Expand All @@ -258,9 +283,9 @@ defimpl LiveReact.Encoder, for: Phoenix.HTML.Form do
defp get_form_validity(%{source: %{valid?: valid}}), do: valid
defp get_form_validity(_), do: true

if Code.ensure_loaded?(Ecto) do
@relations [:embed, :assoc]
@relations [:embed, :assoc]

if Code.ensure_loaded?(Ecto) and Code.ensure_loaded?(Phoenix.HTML.FormData.Ecto.Changeset) do
defp collect_changeset_values(%Ecto.Changeset{} = source, opts) do
data =
Map.new(source.types, fn {field, type} ->
Expand Down
2 changes: 1 addition & 1 deletion lib/live_react/patch.ex
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ defmodule LiveReact.Patch do
defp take_js_string(payload, length), do: take_js_string(payload, payload, length, 0)

defp take_js_string(original, _rest, 0, bytes) do
<<value::binary-size(bytes), rest::binary>> = original
<<value::binary-size(^bytes), rest::binary>> = original
{value, rest}
end

Expand Down
2 changes: 0 additions & 2 deletions lib/live_react/ssr.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ defmodule LiveReact.SSR.NotConfigured do
end

defmodule LiveReact.SSR do
require Logger

@moduledoc """
A behaviour for rendering React components server-side.

Expand Down