Skip to content

Commit

Permalink
updated component methods to match React
Browse files Browse the repository at this point in the history
  • Loading branch information
briandunnington committed Nov 10, 2018
1 parent 415b3f8 commit b20824a
Show file tree
Hide file tree
Showing 14 changed files with 167 additions and 99 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ Roact provides a subset of the full React lifecycle methods. In most cases, the

constructor > init()
componentDidMount > componentDidMount()
componentDidUpdate > componentDidUpdate(prevProps)
shouldComponentUpdate > shouldComponentUpdate()
componentDidUpdate > componentDidUpdate(prevProps, prevState)
shouldComponentUpdate > shouldComponentUpdate(nextProps, nextState)
render > render()

The other React lifecycle methods have either been deprecated by React in recent versions, or are generally not applicable to Roku development.
Expand Down
4 changes: 2 additions & 2 deletions samples/tictactoe/components/Board.brs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ sub init()
m.focusIndex = 0
end sub

sub componentDidMount(p)
sub componentDidMount()
m.focuseater = m.top.findNode("focuseater")
focusOn(0)
end sub

function render(p)
function render()
state = m.top.state

status = ""
Expand Down
2 changes: 1 addition & 1 deletion samples/tictactoe/components/Game.brs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
function render(p)
function render()
return h("Group", {}, [
h("Board"),
h("Label", {text: "Welcome to tic-tac-toe", translation: [1000,72]}),
Expand Down
58 changes: 44 additions & 14 deletions samples/tictactoe/components/RoactComponent.brs
Original file line number Diff line number Diff line change
@@ -1,38 +1,68 @@
'------------------------------------------------------------------
' Override any of these methods in your Roact component
sub init()
m.top.state = {}
end sub

sub componentDidMount(p)
sub componentDidMount()
end sub

sub componentDidUpdate(prevProps)
sub componentDidUpdate(prevProps, prevState)
end sub

function shouldComponentUpdate()
function shouldComponentUpdate(nextProps, nextState)
return true
end function

function render(p)
function render()
?"WARNING: render() not implemented", m.top.id
return invalid
end function

function conditionalRender(p)
if shouldComponentUpdate()
r = render(p)
'------------------------------------------------------------------




'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
' Everything below here is used internally by Roact

sub setState(changedState)
state = m.top.state
newState = {}
newState.append(state)
newState.append(changedState)
RoactUpdateElement(m.top, newState)
end sub

function roactComponentDidMount(ignore)
componentDidMount()
end function

function roactComponentDidUpdate(prevPropsAndState)
componentDidUpdate(prevPropsAndState.props, prevPropsAndState.state)
end function

function roactConditionalRender(nextPropsAndState)
shouldRender = true
if nextPropsAndState <> invalid
shouldRender = shouldComponentUpdate(nextPropsAndState.props, nextPropsAndState.state)
if shouldRender
m.top.setFields({
props: nextPropsAndState.props
state: nextPropsAndState.state
})
end if
end if

if shouldRender
r = render()
r.__instance = strI(rnd(2147483647), 36)
m.top.lastRender = r
end if
return m.top.lastRender
end function

sub setState(changedState)
state = m.top.state
state.append(changedState)
m.top.state = state
RoactUpdateElement(m.top, m.top.props)
end sub

function createHandler(functionName)
return {
node: m.top
Expand Down
6 changes: 3 additions & 3 deletions samples/tictactoe/components/RoactComponent.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
<field id="state" type="assocarray"/>
<field id="children" type="array"/>
<field id="lastRender" type="assocarray"/>
<function name="componentDidMount"/>
<function name="componentDidUpdate"/>
<function name="conditionalRender"/>
<function name="roactComponentDidMount"/>
<function name="roactComponentDidUpdate"/>
<function name="roactConditionalRender"/>
</interface>
</component>
4 changes: 2 additions & 2 deletions samples/tictactoe/components/Square.brs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sub init()
m.font.size = 72
end sub

sub componentDidMount(p)
sub componentDidMount()
findButton()
m.button.observeField("buttonSelected", "buttonClicked")
end sub
Expand All @@ -24,7 +24,7 @@ sub buttonClicked()
executeHandler(props.onClick, {index: props.index})
end sub

function render(p)
function render()
props = m.top.props

val = props.value
Expand Down
54 changes: 29 additions & 25 deletions samples/tictactoe/source/Roact.brs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ function RoactCreateElement(vNode)
props: vNode.props
children: vNode.children
})
vNode = el.callFunc("conditionalRender", invalid)
vNode = el.callFunc("roactConditionalRender", invalid)
child = RoactCreateElement(vNode)
if child <> invalid then el.appendChild(child)
else
Expand All @@ -49,47 +49,55 @@ sub RoactFireComponentDidMount()
if m.mounting <> invalid
for i=(m.mounting.count() - 1) to 0 step -1
el = m.mounting[i]
el.callFunc("componentDidMount", invalid)
el.callFunc("roactComponentDidMount", invalid)
end for
end if
m.mounting = invalid
end sub

sub RoactUpdateElement(parent, prevProps, oldVNode = invalid, newVNode = invalid, index = 0)
'If this is a Roact component, re-render if required
sub RoactUpdateElement(node, newState = invalid, oldVNode = invalid, newVNode = invalid, index = 0)
prevPropsAndState = invalid
didUpdate = false
if parent.hasField("roact")
oldVNode = parent.lastRender
newVNode = parent.callFunc("conditionalRender", invalid)
didUpdate = (prevProps <> invalid AND oldVNode.__instance <> newVNode.__instance)
if node.hasField("roact")
prevPropsAndState = {
props: node.props
state: node.state
}
newProps = node.props
if newVNode <> invalid then newProps = newVNode.props
if newState = invalid then newState = node.state
nextPropsAndState = {
props: newProps
state: newState
}

oldVNode = node.lastRender
newVNode = node.callFunc("roactConditionalRender", nextPropsAndState)
didUpdate = (oldVNode <> invalid AND oldVNode.__instance <> newVNode.__instance)
if NOT didUpdate then return
end if

'Reconcile virtual nodes into actual SG components
if oldVNode = invalid '1. Node did not previously exist
child = RoactCreateElement(newVNode)
if child <> invalid
parent.appendChild(child)
node.appendChild(child)
RoactFireComponentDidMount()
end if
else if newVNode = invalid '2. Node no longer exists
parent.removeChildIndex(index)
node.removeChildIndex(index)
else if newVNode.type <> oldVNode.type '3. Node type changed
child = RoactCreateElement(newVNode)
if child <> invalid
parent.replaceChild(child, index)
node.replaceChild(child, index)
RoactFireComponentDidMount()
end if
else
child = parent.getChild(index)
child = node.getChild(index)
if child.hasField("roact") '4. Node is the same type and is a Roact component
prevProps = child.props
child.setFields({
props: newVNode.props
children: newVNode.children
})
RoactUpdateElement(child, prevProps)
RoactUpdateElement(child, invalid, invalid, newVNode)
else '5. Node is the same type and is a plain SG component
child = parent.getChild(index)
child = node.getChild(index)
offset = 0
if child._intrinsicChildCount <> invalid then offset = child._intrinsicChildCount
RoactUpdateProps(child, oldVNode.props, newVNode.props)
Expand All @@ -98,11 +106,7 @@ sub RoactUpdateElement(parent, prevProps, oldVNode = invalid, newVNode = invalid
length = newLength
if oldLength > length then length = oldLength
for i=0 to length - 1
childPrevProps = invalid
if child.hasField("roact")
childPrevProps = child.props
end if
RoactUpdateElement(child, childPrevProps, oldVNode.children[i], newVNode.children[i], offset + i)
RoactUpdateElement(child, invalid, oldVNode.children[i], newVNode.children[i], offset + i)
end for
if newLength < oldLength
child.removeChildrenIndex(oldLength-newLength, newLength)
Expand All @@ -112,7 +116,7 @@ sub RoactUpdateElement(parent, prevProps, oldVNode = invalid, newVNode = invalid

'If this is a Roact component that updated, trigger componentDidUpdate
if didUpdate
parent.callFunc("componentDidUpdate", prevProps)
node.callFunc("roactComponentDidUpdate", prevPropsAndState)
end if
end sub

Expand Down
4 changes: 2 additions & 2 deletions samples/todo/components/AddTodo.brs
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ sub focusChanged()
m.input.active = m.input.hasFocus()
end sub

sub componentDidMount(p)
sub componentDidMount()
m.input = m.top.findNode("input")
end sub

function render(p)
function render()
return h("TextEditBox", {id: "input", hintText: "add todo..."})
end function

Expand Down
4 changes: 2 additions & 2 deletions samples/todo/components/App.brs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
sub componentDidMount(p)
sub componentDidMount()
m.addTodo = m.top.findNode("addTodo")
m.todoList = m.top.findNode("todoList")
m.addTodo.setFocus(true)
end sub

function render(p)
function render()
return h("Group", {translation: [64, 64]}, [
h("AddTodo", {id: "addTodo"}),
h("TodoList", {id: "todoList", translation: [600, 9]}),
Expand Down
58 changes: 44 additions & 14 deletions samples/todo/components/RoactComponent.brs
Original file line number Diff line number Diff line change
@@ -1,38 +1,68 @@
'------------------------------------------------------------------
' Override any of these methods in your Roact component
sub init()
m.top.state = {}
end sub

sub componentDidMount(p)
sub componentDidMount()
end sub

sub componentDidUpdate(prevProps)
sub componentDidUpdate(prevProps, prevState)
end sub

function shouldComponentUpdate()
function shouldComponentUpdate(nextProps, nextState)
return true
end function

function render(p)
function render()
?"WARNING: render() not implemented", m.top.id
return invalid
end function

function conditionalRender(p)
if shouldComponentUpdate()
r = render(p)
'------------------------------------------------------------------




'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
' Everything below here is used internally by Roact

sub setState(changedState)
state = m.top.state
newState = {}
newState.append(state)
newState.append(changedState)
RoactUpdateElement(m.top, newState)
end sub

function roactComponentDidMount(ignore)
componentDidMount()
end function

function roactComponentDidUpdate(prevPropsAndState)
componentDidUpdate(prevPropsAndState.props, prevPropsAndState.state)
end function

function roactConditionalRender(nextPropsAndState)
shouldRender = true
if nextPropsAndState <> invalid
shouldRender = shouldComponentUpdate(nextPropsAndState.props, nextPropsAndState.state)
if shouldRender
m.top.setFields({
props: nextPropsAndState.props
state: nextPropsAndState.state
})
end if
end if

if shouldRender
r = render()
r.__instance = strI(rnd(2147483647), 36)
m.top.lastRender = r
end if
return m.top.lastRender
end function

sub setState(changedState)
state = m.top.state
state.append(changedState)
m.top.state = state
RoactUpdateElement(m.top, m.top.props)
end sub

function createHandler(functionName)
return {
node: m.top
Expand Down
6 changes: 3 additions & 3 deletions samples/todo/components/RoactComponent.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
<field id="state" type="assocarray"/>
<field id="children" type="array"/>
<field id="lastRender" type="assocarray"/>
<function name="componentDidMount"/>
<function name="componentDidUpdate"/>
<function name="conditionalRender"/>
<function name="roactComponentDidMount"/>
<function name="roactComponentDidUpdate"/>
<function name="roactConditionalRender"/>
</interface>
</component>
4 changes: 2 additions & 2 deletions samples/todo/components/Status.brs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ sub init()
end function)
end sub

sub componentDidMount(p)
sub componentDidMount()
m.label = m.top.findNode("lbl")
end sub

function render(p)
function render()
m.top.translation = m.top.props.translation

status = "Showing: " + m.top.state.filter
Expand Down
Loading

0 comments on commit b20824a

Please sign in to comment.