defmodule Love.React do @moduledoc """ Define reactive functions. A reactive function is tagged with the `@react` attribute and has an arity of 1, accepting the `%LiveView.Socket{}` as its argument, and returning the modified socket. @react to: [:some_prop, :some_state] defp put_changes(socket) do # ... end Reactive functions can subscribe to changes in state assigns or, in Live Compoents, prop assigns. ## Options for `@react` - `:to` - required; an atom, or list of atoms, specifying the state and prop fields to subscribe to - `:repeats?` - optional, defaults to `false`; when `true`, disables infinite loop detection ## Infinite Loop Detection If a reactive function is executed multiple times during a single update cycle, this indicates a possible infinite loop of reactive callbacks, and a `RuntimeError` will be raised. This check can be bypassed with the `repeats?: true` option on the `@react` attribute. ## Example defmodule MyComponent do use Phoenix.LiveComponent use Love.Component prop :first_name prop :last_name state :big_display_name state :display_name state :full_name?, default: false # Triggered when there are any changes to these props or state @react to: [:first_name, :last_name, :full_name?] defp put_display_name(socket) do if socket.assigns.full_name? do put_state(socket, display_name: "\#{socket.assigns.first_name, socket.assigns.last_name}") else put_state(socket, display_name: socket.assigns.first_name) end end # Triggered after put_display_name/1 finishes @react to: :display_name defp put_big_display_name(socket) do put_state(socket, big_display_name: String.upcase(socket.assigns.display_name)) end end """ alias Love.Internal defmacro __using__(_opts) do quote do @on_definition {Love.Internal, :on_definition} @before_compile Love.React end end defmacro __before_compile__(env) do # Delay these function definitions until as late as possible, so we can ensure the attributes # are fully set up (i.e. wait for __on_definition__/6 to evaluate first!) [ Internal.before_compile_define_meta_fns(env, [:react]), Internal.before_compile_define_react_wrappers(env) ] end end