Skip to content

Instantly share code, notes, and snippets.

@jgaskins
Last active February 16, 2019 13:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jgaskins/d77e18b8f784b3d8afc362c01a2325ec to your computer and use it in GitHub Desktop.
Save jgaskins/d77e18b8f784b3d8afc362c01a2325ec to your computer and use it in GitHub Desktop.
Hooks implementation for Clearwater
module Hooks
def self.component *attrs, &render
Class.new(Component) do
attr_reader *attrs
define_method :initialize do |**props|
super()
attrs.each { |attr| `self[#{attr}] = #{props[attr]}` }
end
define_method :run do
@state_index = 0
@effect_index = 0
instance_exec &render
end
end
end
require 'clearwater/black_box_node'
class Component
include Clearwater::Component
include Clearwater::BlackBoxNode
attr_reader :states, :effect_markers, :cleanup_hooks, :vdom
def initialize
@states = []
@effect_markers = []
@cleanup_hooks = []
@render_callbacks = []
@effect_index = 0
@state_index = 0
end
def node
@node = run
end
def mount element
@vdom = Clearwater::VirtualDOM::Document.pre_rendered(element, node)
@can_render = true
end
def update previous
@states = previous.states
@effect_markers = previous.effect_markers
@cleanup_hooks = previous.cleanup_hooks
@vdom = previous.vdom
@can_render = true
previous.cancel_renders
@vdom.render run
nil
end
def unmount
cancel_renders
@cleanup_hooks.each do |block|
block.call if block
end
end
def cancel_renders
@can_render = false
end
def use_state initial
current_index = @state_index
@states[current_index] ||= initial
setter = proc do |new_value|
@states[current_index] = new_value
call
end
@state_index += 1
[@states[current_index], setter]
end
def use_effect *markers, &effect
current_index = @effect_index
if @effect_markers[current_index] != markers
@effect_markers[current_index] = markers
if @cleanup_hooks[current_index]
@cleanup_hooks[current_index].call
end
effect.call
end
@effect_index += 1
end
def cleanup &block
@cleanup_hooks[@effect_index] = block
end
def call &block
@render_callbacks << block if block
return if @will_render || !@can_render
@will_render = true
Bowser.window.animation_frame do
@will_render = false
@vdom.render run
@render_callbacks.each(&:call)
@render_callbacks = []
end
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment