-
Notifications
You must be signed in to change notification settings - Fork 8
Add useReducer API #34
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -52,9 +52,6 @@ module Make = (ReconcilerImpl: Reconciler) => { | |
and t = container | ||
and childInstances = list(instance); | ||
|
||
type stateUpdateFunction('t) = 't => unit; | ||
type stateResult('t) = ('t, stateUpdateFunction('t)); | ||
|
||
type node = ReconcilerImpl.node; | ||
type primitives = ReconcilerImpl.primitives; | ||
|
||
|
@@ -382,7 +379,7 @@ module Make = (ReconcilerImpl: Reconciler) => { | |
/* Only both replacing node if the primitives are different */ | ||
switch (newInstance.component.element, i.component.element) { | ||
| (Primitive(newPrim), Primitive(oldPrim)) => | ||
if (oldPrim != newPrim) { | ||
if (oldPrim !== newPrim) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is probably the most relevant change. Because we were using structural equality before, when the primitives would contain any function in side (like, say, a I am not sure about the perf implications. This change will lead to the reconciler rendering much more often but on the other hand the checks should be much faster too. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah interesting, thanks for calling it out! Would've been easy to miss 😄
Good catch! Yes, that makes sense that it is problematic in this case. Comparing 'functions' is not really doable in the OCaml sense like it is in JS.
Yes, good point, I suspect it will depend on how much work it is to create a new 'node' too. Would really need benchmarks to decide if it is a bottleneck or not. But I'm OK with this going in since it behaves correctly and all the tests are green. We can focus on addressing the performance once we find bottlenecks / have benchmarks to examine. I created #37 to examine this in more depth. |
||
/* Check if the primitive type is the same - if it is, we can simply update the node */ | ||
/* If not, we'll replace the node */ | ||
if (Utility.areConstructorsEqual(oldPrim, newPrim)) { | ||
|
@@ -479,18 +476,20 @@ module Make = (ReconcilerImpl: Reconciler) => { | |
newChildInstances^; | ||
}; | ||
|
||
let useState = (v: 't) => { | ||
let state = __globalState^; | ||
let n = ComponentState.popOldState(state, v); | ||
|
||
let updateFunction = ComponentState.pushNewState(state, n); | ||
let useReducer = | ||
(reducer: ('state, 'action) => 'state, initialState: 'state) => { | ||
let globalState = __globalState^; | ||
let componentState = | ||
ComponentState.popOldState(globalState, initialState); | ||
|
||
/* let updateFunction = (_n) => { (); }; */ | ||
let (getState, updateState) = | ||
ComponentState.pushNewState(globalState, componentState); | ||
|
||
let currentContext = ComponentState.getCurrentContext(state); | ||
let currentContext = ComponentState.getCurrentContext(globalState); | ||
|
||
let setState = (context: ref(option(instance)), newVal: 't) => { | ||
updateFunction(newVal); | ||
let dispatch = (context: ref(option(instance)), action: 'action) => { | ||
let newVal = reducer(getState(), action); | ||
updateState(newVal); | ||
switch (context^) { | ||
| Some(i) => | ||
let {rootNode, component, _} = i; | ||
|
@@ -503,7 +502,20 @@ module Make = (ReconcilerImpl: Reconciler) => { | |
}; | ||
}; | ||
|
||
(n, setState(currentContext)); | ||
(componentState, dispatch(currentContext)); | ||
}; | ||
|
||
type useStateAction('a) = | ||
| SetState('a); | ||
let useStateReducer = (_state, action) => | ||
switch (action) { | ||
| SetState(newState) => newState | ||
}; | ||
let useState = initialState => { | ||
let (componentState, dispatch) = | ||
useReducer(useStateReducer, initialState); | ||
let setState = newState => dispatch(SetState(newState)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool, I like how you implemented |
||
(componentState, setState); | ||
}; | ||
|
||
let updateContainer = (container, component) => { | ||
|
@@ -520,4 +532,4 @@ module Make = (ReconcilerImpl: Reconciler) => { | |
module State = State; | ||
module Event = Event; | ||
module Utility = Utility; | ||
module Object = Object; | ||
module Object = Object; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,7 +26,7 @@ module Make = (StateContextImpl: StateContext) => { | |
mutable newState: HeterogenousMutableList.t, | ||
}; | ||
|
||
type updateFunction('a) = 'a => unit; | ||
type getterAndUpdater('a) = (unit => 'a, 'a => unit); | ||
|
||
let noneContext = () => ref(None); | ||
|
||
|
@@ -51,20 +51,22 @@ module Make = (StateContextImpl: StateContext) => { | |
curr; | ||
}; | ||
|
||
let pushNewState: (t, 'a) => updateFunction('a) = | ||
let pushNewState: (t, 'a) => getterAndUpdater('a) = | ||
(state: t, currentVal: 'a) => { | ||
let updatedVal: ref(Object.t) = ref(Object.to_object(currentVal)); | ||
state.newState = List.append(state.newState, [updatedVal]); | ||
let ret: updateFunction('a) = | ||
let ret: getterAndUpdater('a) = ( | ||
() => Object.of_object(updatedVal^), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not 100% sure this is necessary... but I added it just to be sure, for cases when there are two actions being dispatched in the same render. |
||
(newVal: 'a) => { | ||
updatedVal := Object.to_object(newVal); | ||
(); | ||
}; | ||
}, | ||
); | ||
ret; | ||
}; | ||
|
||
let getCurrentContext = (state: t) => state.context^; | ||
|
||
let getNewState: t => HeterogenousMutableList.t = | ||
(state: t) => state.newState; | ||
}; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exploring the feasibility of making the DOM reconciler primitives more similar to those in Revery 😄