Skip to content
This repository was archived by the owner on Oct 19, 2018. It is now read-only.

Commit 3495f4b

Browse files
committed
closes #155
1 parent a761248 commit 3495f4b

File tree

3 files changed

+113
-20
lines changed

3 files changed

+113
-20
lines changed

.rubocop.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ Style/MutableConstant:
66

77
Lint/LiteralInCondition:
88
Enabled: false
9+
10+
Style/CommandLiteral:
11+
EnforcedStyle: mixed

lib/react/component.rb

Lines changed: 37 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -90,32 +90,49 @@ def component_will_receive_props(next_props)
9090
self.class.process_exception(e, self)
9191
end
9292

93-
def props_changed?(next_props)
94-
return true unless props.keys.sort == next_props.keys.sort
95-
props.detect { |k, v| `#{next_props[k]} != #{params[k]}`}
96-
end
97-
98-
def should_component_update?(next_props, next_state)
93+
def should_component_update?(native_next_props, native_next_state)
9994
State.set_state_context_to(self) do
100-
next_props = Hash.new(next_props)
101-
if self.respond_to?(:needs_update?)
102-
!!self.needs_update?(next_props, Hash.new(next_state))
103-
elsif false # switch to true to force updates per standard react
104-
true
105-
elsif props_changed? next_props
106-
true
107-
elsif `!next_state != !#{@native}.state`
108-
true
109-
elsif `!next_state && !#{@native}.state`
110-
false
111-
elsif `next_state["***_state_updated_at-***"] != #{@native}.state["***_state_updated_at-***"]`
112-
true
95+
next_params = Hash.new(native_next_props)
96+
if respond_to?(:needs_update?)
97+
call_needs_update(next_params, native_next_state)
11398
else
114-
false
99+
!!(props_changed?(next_params) || native_state_changed?(native_next_state))
115100
end.to_n
116101
end
117102
end
118103

104+
def call_needs_update(next_params, native_next_state)
105+
component = self
106+
next_params.define_singleton_method(:changed?) do
107+
@changing ||= component.props_changed?(self)
108+
end
109+
next_state = Hash.new(native_next_state)
110+
next_state.define_singleton_method(:changed?) do
111+
@changing ||= component.native_state_changed?(native_next_state)
112+
end
113+
!!needs_update?(next_params, next_state)
114+
end
115+
116+
def native_state_changed?(next_state)
117+
%x{
118+
var normalized_next_state =
119+
(!#{next_state} || Object.keys(#{next_state}).length === 0 || #{nil} == next_state) ? false : #{next_state}
120+
var normalized_current_state =
121+
(!#{@native}.state || Object.keys(#{@native}.state).length === 0 || #{nil} == #{@native}.state) ? false : #{@native}.state
122+
if (!normalized_current_state != !normalized_next_state) return(true)
123+
if (!normalized_current_state && !normalized_next_state) return(false)
124+
if (!normalized_current_state['***_state_updated_at-***'] ||
125+
!normalized_next_state['***_state_updated_at-***']) return(true)
126+
return (normalized_current_state['***_state_updated_at-***'] !=
127+
normalized_next_state['***_state_updated_at-***'])
128+
}
129+
end
130+
131+
def props_changed?(next_params)
132+
(props.keys.sort != next_params.keys.sort) ||
133+
next_params.detect { |k, _v| `#{next_params[k]} != #{@native}.props[#{k}]` }
134+
end
135+
119136
def component_will_update(next_props, next_state)
120137
State.set_state_context_to(self) { self.run_callback(:before_update, Hash.new(next_props), Hash.new(next_state)) }
121138
@props_wrapper = self.class.props_wrapper.new(Hash.new(next_props), @props_wrapper)

spec/react/component_spec.rb

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,79 @@ def render
705705
end
706706
end
707707

708+
describe '.params_changed?' do
709+
710+
before(:each) do
711+
stub_const 'Foo', Class.new(React::Component::Base)
712+
Foo.define_method :needs_update? do |next_params, next_state|
713+
next_params.changed?
714+
end
715+
@foo = Foo.new
716+
end
717+
718+
it "returns false if new and old params are the same" do
719+
@foo.instance_variable_set("@native", `{props: {value1: 1, value2: 2}}`)
720+
expect(@foo.should_component_update?(`{value2: 2, value1: 1}`, `null`)).to be_falsy
721+
end
722+
723+
it "returns true if new and old params are have different values" do
724+
@foo.instance_variable_set("@native", `{props: {value1: 1, value2: 2}}`)
725+
expect(@foo.should_component_update?(`{value2: 2, value1: 2}`, `null`)).to be_truthy
726+
end
727+
728+
it "returns true if new and old params are have different keys" do
729+
@foo.instance_variable_set("@native", `{props: {value1: 1, value2: 2}}`)
730+
expect(@foo.should_component_update?(`{value2: 2, value1: 1, value3: 3}`, `null`)).to be_truthy
731+
end
732+
end
733+
734+
describe '#state_changed?' do
735+
736+
empties = [`{}`, `undefined`, `null`, `false`]
737+
738+
before(:each) do
739+
stub_const 'Foo', Class.new(React::Component::Base)
740+
Foo.define_method :needs_update? do |next_params, next_state|
741+
next_state.changed?
742+
end
743+
@foo = Foo.new
744+
end
745+
746+
it "returns false if both new and old states are empty" do
747+
empties.each do |empty1|
748+
empties.each do |empty2|
749+
@foo.instance_variable_set("@native", `{state: #{empty1}}`)
750+
expect(@foo.should_component_update?(`{}`, empty2)).to be_falsy
751+
end
752+
end
753+
end
754+
755+
it "returns true if old state is empty, but new state is not" do
756+
empties.each do |empty|
757+
@foo.instance_variable_set("@native", `{state: #{empty}}`)
758+
expect(@foo.should_component_update?(`{}`, `{foo: 12}`)).to be_truthy
759+
end
760+
end
761+
762+
it "returns true if new state is empty, but old state is not" do
763+
empties.each do |empty|
764+
@foo.instance_variable_set("@native", `{state: {foo: 12}}`)
765+
expect(@foo.should_component_update?(`{}`, empty)).to be_truthy
766+
end
767+
end
768+
769+
it "returns true if new state and old state have different time stamps" do
770+
@foo.instance_variable_set("@native", `{state: {'***_state_updated_at-***': 12}}`)
771+
expect(@foo.should_component_update?(`{}`, `{'***_state_updated_at-***': 13}`)).to be_truthy
772+
end
773+
774+
it "returns false if new state and old state have the same time stamps" do
775+
@foo.instance_variable_set("@native", `{state: {'***_state_updated_at-***': 12}}`)
776+
expect(@foo.should_component_update?(`{}`, `{'***_state_updated_at-***': 12}`)).to be_falsy
777+
end
778+
779+
end
780+
708781
describe '#children' do
709782
before(:each) do
710783
stub_const 'Foo', Class.new

0 commit comments

Comments
 (0)