From what it looks like in the code:
https://github.com/phoenixframework/phoenix_live_view/blob/2869e28d16b2b514118e3c9c492ef206a8ca3b62/lib/phoenix_component.ex#L946
def live_render(%Socket{} = parent, view, opts) do
Static.nested_render(parent, view, opts)
end
https://github.com/phoenixframework/phoenix_live_view/blob/2869e28d16b2b514118e3c9c492ef206a8ca3b62/lib/phoenix_live_view/static.ex#L212
def nested_render(
%Socket{endpoint: endpoint, transport_pid: transport_pid} = parent,
view,
opts
) do
config = load_live!(view, :view)
container = container(config, opts)
sticky? = Keyword.get(opts, :sticky, false)
child_id =
opts[:id] ||
raise ArgumentError,
"an :id is required when rendering child LiveView. " <>
"The :id must uniquely identify the child."
socket =
Utils.configure_socket(
%Socket{
id: to_string(child_id),
view: view,
endpoint: endpoint,
root_pid: if(sticky?, do: nil, else: parent.root_pid), ################
parent_pid: if(sticky?, do: nil, else: self()), ##################
router: parent.router
},
https://github.com/phoenixframework/phoenix_live_view/blob/2869e28d16b2b514118e3c9c492ef206a8ca3b62/lib/phoenix_live_view/channel.ex#L1150
defp mount(%{"session" => session_token} = params, from, phx_socket) do
%Phoenix.Socket{endpoint: endpoint, topic: topic} = phx_socket
case Session.verify_session(endpoint, topic, session_token, params["static"]) do
{:ok, %Session{} = verified} ->
%Phoenix.Socket{private: %{connect_info: connect_info}} = phx_socket
case connect_info do
%{session: nil} ->
GenServer.reply(from, {:error, %{reason: "stale"}})
{:stop, :shutdown, :no_state}
%{} ->
with {:ok, %Session{view: view} = new_verified, route, url} <-
authorize_session(verified, endpoint, params),
{:ok, config} <- load_live_view(view) do
verified_mount(
new_verified,
config,
route,
url,
params,
from,
phx_socket,
connect_info
)
defp verified_mount(
%Session{} = verified,
config,
route,
url,
params,
from,
phx_socket,
connect_info
) do
%Session{
id: id,
view: view,
root_view: root_view,
parent_pid: parent,
root_pid: root_pid,
session: verified_user_session,
assign_new: assign_new,
router: router
} = verified
%Phoenix.Socket{
endpoint: endpoint,
transport_pid: transport_pid
} = phx_socket
Process.put(:"$initial_call", {view, :mount, 3})
case params do
%{"caller" => {pid, _}} when is_pid(pid) -> Process.put(:"$callers", [pid])
_ -> Process.put(:"$callers", [transport_pid])
end
# Optional parameter handling
connect_params = params["params"]
# Optional verified parts
flash = verify_flash(endpoint, verified, params["flash"], connect_params)
# connect_info is either a Plug.Conn during tests or a Phoenix.Socket map
socket_session = Map.get(connect_info, :session, %{})
Process.monitor(transport_pid)
load_csrf_token(endpoint, socket_session)
socket = %Socket{
endpoint: endpoint,
view: view,
transport_pid: transport_pid,
parent_pid: parent,
root_pid: root_pid || self(),
id: id,
router: router
}
So each render_live will assign the itself - the renderer pid as a parent.
for root_pid, it will pass what it itself got from its parent. It seems when the socket is created and mounted, the creating process (the socket main channel?) set it self as the root on the newly created socket.