Class: React::State

Inherits:
Object
  • Object
show all
Defined in:
lib/react/state.rb

Constant Summary collapse

ALWAYS_UPDATE_STATE_AFTER_RENDER =

if on server then we don’t wait to update the state

Hyperloop.on_client?

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.current_observerObject (readonly)

Returns the value of attribute current_observer.



8
9
10
# File 'lib/react/state.rb', line 8

def current_observer
  @current_observer
end

Class Method Details

.bulk_updateObject



14
15
16
17
18
19
20
# File 'lib/react/state.rb', line 14

def bulk_update
  saved_bulk_update_flag = @bulk_update_flag
  @bulk_update_flag = true
  yield
ensure
  @bulk_update_flag = saved_bulk_update_flag
end

.get_state(object, name, current_observer = @current_observer) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
# File 'lib/react/state.rb', line 50

def get_state(object, name, current_observer = @current_observer)
  # get current value of name for object, remember that the current object depends on this state,
  # current observer can be overriden with last param
  if current_observer && !new_observers[current_observer][object].include?(name)
    new_observers[current_observer][object] << name
  end
  if @delayed_updates && @delayed_updates[object][name]
    @delayed_updates[object][name][1] << current_observer
  end
  states[object][name]
end

.has_observers?(object, name) ⇒ Boolean

Returns:

  • (Boolean)


10
11
12
# File 'lib/react/state.rb', line 10

def has_observers?(object, name)
  !observers_by_name[object][name].empty?
end

.ignore_bulk_updates(*args) ⇒ Object

React already will batch together updates inside of event handlers so we don’t have to, and having Hyperstack batch them outside of the event handler causes INPUT/TEXT/SELECT s not to work properly. This method is called by the Component event wrapper.



26
27
28
29
30
31
32
# File 'lib/react/state.rb', line 26

def ignore_bulk_updates(*args)
  saved_ignore_bulk_update_flag = @ignore_bulk_update_flag
  @ignore_bulk_update_flag = true
  yield(*args)
ensure
  @ignore_bulk_update_flag = saved_ignore_bulk_update_flag
end

.initialize_states(object, initial_values) ⇒ Object

initialize objects’ name/value pairs



46
47
48
# File 'lib/react/state.rb', line 46

def initialize_states(object, initial_values) # initialize objects' name/value pairs
  states[object].merge!(initial_values || {})
end

.is_observing?(object, name, current_observer) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
# File 'lib/react/state.rb', line 103

def is_observing?(object, name, current_observer)
  current_observer && observers_by_name[object][name].include?(current_observer)
end

.removeObject

call after component is unmounted



123
124
125
126
127
128
129
130
131
# File 'lib/react/state.rb', line 123

def remove # call after component is unmounted
  raise "remove called outside of watch block" unless @current_observer
  current_observers[@current_observer].each do |object, names|
    names.each do |name|
      observers_by_name[object][name].delete(@current_observer)
    end
  end
  current_observers.delete(@current_observer)
end

.set_state(object, name, value, delay = ALWAYS_UPDATE_STATE_AFTER_RENDER) ⇒ Object

ReactDOM.unstable_batchedUpdates does not seem to improve things here, ill leave it here commented for reference and later investigation if ‘ReactDOM.unstable_batchedUpdates !== undefined`

%x{
  ReactDOM.unstable_batchedUpdates(function(){
    #{updates.each { |observer, args| observer.update_react_js_state(*args) }}
  });
}

else # run the other one



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/react/state.rb', line 71

def set_state(object, name, value, delay=ALWAYS_UPDATE_STATE_AFTER_RENDER)
  states[object][name] = value
  delay = false if object.respond_to?(:set_state_synchronously?) && object.set_state_synchronously?
  if !@ignore_bulk_update_flag && (delay || @bulk_update_flag)
    @delayed_updates ||= Hash.new { |h, k| h[k] = {} }
    @delayed_updates[object][name] = [value, Set.new]
    @delayed_updater ||= after(0.001) do
      delayed_updates = @delayed_updates
      @delayed_updates = Hash.new { |h, k| h[k] = {} } # could this be nil???
      @delayed_updater = nil
      updates = Hash.new { |hash, key| hash[key] = Array.new }
      delayed_updates.each do |object, name_hash|
        name_hash.each do |name, value_and_set|
          set_state2(object, name, value_and_set[0], updates, value_and_set[1])
        end
      end
      updates.each { |observer, args| observer.update_react_js_state(*args) }
    end
  elsif @rendering_level == 0
    updates = Hash.new { |hash, key| hash[key] = Array.new }
    set_state2(object, name, value, updates)
    updates.each { |observer, args| observer.update_react_js_state(*args) }
  end
  value
ensure
  'Disabling JIT for Safari bug'
end

.set_state2(object, name, value, updates, exclusions = nil) ⇒ Object



34
35
36
37
38
39
40
41
42
43
44
# File 'lib/react/state.rb', line 34

def set_state2(object, name, value, updates, exclusions = nil)
  # set object's name state to value, tell all observers it has changed.
  # Observers must implement update_react_js_state
  object_needs_notification = object.respond_to?(:update_react_js_state)
  observers_by_name[object][name].dup.each do |observer|
    next if exclusions && exclusions.include?(observer)
    updates[observer] += [object, name, value]
    object_needs_notification = false if object == observer
  end
  updates[object] += [nil, name, value] if object_needs_notification
end

.set_state_context_to(observer, rendering = nil) ⇒ Object

wrap all execution that may set or get states in a block so we know which observer is executing



133
134
135
136
137
138
139
140
141
142
143
# File 'lib/react/state.rb', line 133

def set_state_context_to(observer, rendering = nil) # wrap all execution that may set or get states in a block so we know which observer is executing
  saved_current_observer = @current_observer
  @current_observer = observer
  @rendering_level += 1 if rendering
  return_value = yield
  return_value
ensure
  @current_observer = saved_current_observer
  @rendering_level -= 1 if rendering
  return_value
end

.statesObject



145
146
147
# File 'lib/react/state.rb', line 145

def states
  @states ||= Hash.new { |h, k| h[k] = {} }
end

.update_states_to_observe(current_observer = @current_observer) ⇒ Object

should be called after the last after_render callback, currently called after components render method



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/react/state.rb', line 107

def update_states_to_observe(current_observer = @current_observer)  # should be called after the last after_render callback, currently called after components render method
  raise "update_states_to_observer called outside of watch block" unless current_observer
  current_observers[current_observer].each do |object, names|
    names.each do |name|
      observers_by_name[object][name].delete(current_observer)
    end
  end
  observers = current_observers[current_observer] = new_observers[current_observer]
  new_observers.delete(current_observer)
  observers.each do |object, names|
    names.each do |name|
      observers_by_name[object][name] << current_observer
    end
  end
end

.will_be_observing?(object, name, current_observer) ⇒ Boolean

Returns:

  • (Boolean)


99
100
101
# File 'lib/react/state.rb', line 99

def will_be_observing?(object, name, current_observer)
  current_observer && new_observers[current_observer][object].include?(name)
end