Skip to content

Commit

Permalink
Rendering a component must reconcile against previous DOM state
Browse files Browse the repository at this point in the history
The `renderComponent` function incorrectly presumed that `prevRender`
from the component context must be the previous DOM state, however
elements may have been shuffled/removed between component renders for
persistent component pointers.

Fixes #123
  • Loading branch information
pdf committed Jun 30, 2017
1 parent 8285cb1 commit 1ea2739
Showing 1 changed file with 6 additions and 5 deletions.
11 changes: 6 additions & 5 deletions dom.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ func (h *HTML) reconcile(prev *HTML) {
prevChildRender, ok := prevChild.(*HTML)
if !ok {
prevChildRender = prevChild.(Component).Context().prevRender
prevChild.(Component).Context().prevRender = nil
}
removeNode(prevChildRender.node)
if u, ok := prevChild.(Unmounter); ok {
Expand Down Expand Up @@ -335,7 +336,7 @@ func Rerender(c Component) {
if prevRender == nil {
panic("vecty: Rerender invoked on Component that has never been rendered")
}
nextRender, skip := renderComponent(c)
nextRender, skip := renderComponent(c, prevRender)
if skip {
return
}
Expand Down Expand Up @@ -379,7 +380,7 @@ func render(c ComponentOrHTML, prevRender *HTML) (h *HTML, skip bool) {
v.reconcile(prevRender)
return v, false
case Component:
return renderComponent(v)
return renderComponent(v, prevRender)
default:
panic(fmt.Sprintf("vecty: encountered invalid ComponentOrHTML %T", c))
}
Expand All @@ -388,7 +389,7 @@ func render(c ComponentOrHTML, prevRender *HTML) (h *HTML, skip bool) {
// renderComponent handles rendering the given Component into *HTML. If skip ==
// true is returned, the Component's SkipRender method has signaled the
// component does not need to be rendered and h == nil is returned.
func renderComponent(comp Component) (h *HTML, skip bool) {
func renderComponent(comp Component, prevRender *HTML) (h *HTML, skip bool) {
// Now that we know we are rendering the component, restore friendly
// relations between the component and the previous component.
if comp != comp.Context().prevComponent {
Expand Down Expand Up @@ -419,7 +420,7 @@ func renderComponent(comp Component) (h *HTML, skip bool) {
}

// Restore the actual rendered HTML.
nextRender.reconcile(comp.Context().prevRender)
nextRender.reconcile(prevRender)

// Update the context to consider this render.
comp.Context().prevRender = nextRender
Expand All @@ -431,7 +432,7 @@ func renderComponent(comp Component) (h *HTML, skip bool) {
// RenderBody renders the given component as the document body. The given
// Component's Render method must return a "body" element.
func RenderBody(body Component) {
nextRender, skip := renderComponent(body)
nextRender, skip := renderComponent(body, nil)
if skip {
panic("vecty: RenderBody Component.SkipRender returned true")
}
Expand Down

0 comments on commit 1ea2739

Please sign in to comment.