Skip to content

Commit f84c484

Browse files
committed
fix(accordion): moving to state-based re-rendering instead of calling forceUpdate to try to prevent race conditions
1 parent e345efd commit f84c484

File tree

1 file changed

+22
-23
lines changed

1 file changed

+22
-23
lines changed

core/src/components/accordion/accordion.tsx

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { ComponentInterface } from '@stencil/core';
2-
import { Component, Element, Host, Prop, State, Watch, forceUpdate, h } from '@stencil/core';
2+
import { Component, Element, Host, Prop, State, Watch, h } from '@stencil/core';
33
import { addEventListener, getElementRoot, raf, removeEventListener, transitionEndAsync } from '@utils/helpers';
44
import { chevronDown } from 'ionicons/icons';
55

@@ -48,20 +48,19 @@ export class Accordion implements ComponentInterface {
4848
private headerEl: HTMLDivElement | undefined;
4949

5050
private currentRaf: number | undefined;
51-
/**
52-
* If true, the next animation will be skipped.
53-
* We want to skip the animation when the accordion
54-
* is expanded or collapsed on the initial load.
55-
* This prevents the accordion from animating when
56-
* it starts expanded or collapsed.
57-
*/
58-
private skipNextAnimation = true;
5951

6052
@Element() el?: HTMLElement;
6153

6254
@State() state: AccordionState = AccordionState.Collapsed;
6355
@State() isNext = false;
6456
@State() isPrevious = false;
57+
/**
58+
* Tracks whether the component has completed its initial render.
59+
* Animations are disabled until after the first render completes.
60+
* This prevents the accordion from animating when it starts
61+
* expanded or collapsed on initial load.
62+
*/
63+
@State() hasRendered = false;
6564

6665
/**
6766
* The value of the accordion. Defaults to an autogenerated
@@ -132,14 +131,14 @@ export class Accordion implements ComponentInterface {
132131
}
133132

134133
componentDidRender() {
135-
if (this.skipNextAnimation) {
136-
this.skipNextAnimation = false;
137-
/**
138-
* The initial render disables animations so framework-provided
139-
* values do not cause the accordion to animate. Force a repaint
140-
* so subsequent user interactions animate as expected.
141-
*/
142-
forceUpdate(this);
134+
/**
135+
* After the first render completes, mark that we've rendered.
136+
* Setting this state property triggers a re-render, at which point
137+
* animations will be enabled. This ensures animations are disabled
138+
* only for the initial render, avoiding unwanted animations on load.
139+
*/
140+
if (!this.hasRendered) {
141+
this.hasRendered = true;
143142
}
144143
}
145144

@@ -315,7 +314,12 @@ export class Accordion implements ComponentInterface {
315314
* of what is set in the config.
316315
*/
317316
private shouldAnimate = () => {
318-
if (this.skipNextAnimation) {
317+
/**
318+
* Don't animate until after the first render cycle completes.
319+
* This prevents animations on initial load when accordions
320+
* start in an expanded or collapsed state.
321+
*/
322+
if (!this.hasRendered) {
319323
return false;
320324
}
321325

@@ -351,11 +355,6 @@ export class Accordion implements ComponentInterface {
351355
const value = accordionGroup.value;
352356

353357
const shouldExpand = Array.isArray(value) ? value.includes(accordionValue) : value === accordionValue;
354-
const shouldDisableAnimation = initialUpdate && shouldExpand;
355-
356-
if (shouldDisableAnimation) {
357-
this.skipNextAnimation = true;
358-
}
359358

360359
if (shouldExpand) {
361360
this.expandAccordion(initialUpdate);

0 commit comments

Comments
 (0)