Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React multiple instances of same component are getting same state

Tags:

reactjs

state

I have a React Component and I am creating 2 copies of it. However, when the state of 1 of them is updated, it updates the 2nd one too. I am not sure what is causing this.

Here is my code:

This is the place where I am using 2 components:

{this.state.selectedTab === 0 ?
    <Carousel
       size={1}
       cultureInfo={this.state.cultureInfo}
       collaboratorError={this.state.activeCollaborationError}
       getPinnedError={this.state.getPinnedUsersError}
       pinActionError={this.state.isPinnedServerError}
       user={this.state.activeCollaboratorContactsData}
       isPinnedTab={false}
       startDate={this.state.startDate}
       isMapped={this.state.isMapped}
       resetPosition={this.state.resetCollabCarousel}
       isVisible={this.state.selectedTab === 0 }
/>
:
<Carousel
  size={1}
  cultureInfo={this.state.cultureInfo}
  collaboratorError={this.state.activeCollaborationError}
  getPinnedError={this.state.getPinnedUsersError}
  pinActionError={this.state.isPinnedServerError}
  user={this.state.pinnedUsers}
  isPinnedTab={true}
  startDate={this.state.startDate}
  isMapped={this.state.isMapped}
  resetPosition={this.state.resetPinnedCarousel}
  isVisible={this.state.selectedTab === 1}
/>
}

Here is the Carousel Code:

interface ICarouselProps {
 size: number;
 cultureInfo: CultureInfo;
 collaboratorError: Error.DataLayerError;
 getPinnedError: Error.DataLayerError;
 pinActionError: Error.DataLayerError;
 user: ActiveCollaboratorContact[];
 isPinnedTab: boolean;
 startDate: Date;
 isMapped: boolean;
 resetPosition: boolean;
 isVisible: boolean;
}

interface ICarouselState {
 position: number;
 width: number;
 isActiveNext: boolean;
 isActivePrev: boolean;
 isActive: number;
 }

 const numSlides = 2;
 const width = 100;
 const move = width / numSlides;
 const max = width - move;
 const min = -max;

 const numOfCards = 4;

 export default class Carousel extends BaseComponent<ICarouselProps,     

      ICarouselState> {
constructor() {
    super();
    this.resetState();
}

componentWillReceiveProps(newProps: ICarouselProps): void {
    if (newProps && newProps.resetPosition) {
        this.resetState();
    }
}

doRender(): React.ReactElement<{}> {
    let wrapperWidth: number;
    let widthStyle: string;
    wrapperWidth = (this.state as ICarouselState).width;

    const style:  React.CSSProperties = {
        WebkitTransform: "translateX(" + this.state.position + "%)",
        transform: "translateX(" + this.state.position + "%)",
        MozTransform: "translateX(" + this.state.position + "%)",
        msTransform: "translateX(" + this.state.position + "%)",
        OTransform: "translateX(" + this.state.position + "%)",
        width: wrapperWidth + "%"
    } as React.CSSProperties;
    const slideWidth:  React.CSSProperties = {width: move + "%"} as React.CSSProperties;
    let nextIsDisabled: boolean;
    let prevIsDisabled: boolean;
    let slideActive: string;

    widthStyle = (this.props.size === 0) ? styles.vCard : styles.hCard;
    nextIsDisabled = !this.state.isActiveNext;
    prevIsDisabled = !this.state.isActivePrev;
    slideActive = "slideActive" + this.state.isActive;

        const totalUsers = this.props.user.length;
        const articles: JSX.Element[] = [];


        for (let i = 0; i < 2; i++) {
            const cards: JSX.Element[] = [];
            for (let j = 0; j < numOfCards; j++) {
                const userIndex = i * numOfCards + j;
                if (userIndex < totalUsers) {
                    const card: JSX.Element = <Card
                        cultureInfo={this.props.cultureInfo}
                        user={this.props.user[userIndex]}
                        startDate={this.props.startDate}
                        extraMargin={userIndex % numOfCards === 0}
                    />;
                    cards.push(card);
                }
            }
            const article: JSX.Element =
                    <article className={styles.slideSingle}
                            tabIndex={0}
                            style={slideWidth}>
                        {cards}
                    </article>;
            articles.push(article);
        }
        return this.props.isVisible ?
                <div>
                    <div className={widthStyle + " " + styles.carousel + " " + slideActive} tabIndex={-1} id="Carousel">
                        <div className={styles.slideWrapper}
                            style={style}>
                            {articles}
                        </div>
                        <nav className={styles.nav}>
                            <ul className={styles.arrows}>
                                <li className={styles.stepLeft}>
                                <a disabled={prevIsDisabled} aria-disabled={prevIsDisabled} className={styles.previous} href="#"
                                    tabIndex={0}
                                    onClick = {this.prevSlideClicked}>
                                    BUTTONPREVTEXT
                                </a>
                                </li>
                                <li className={styles.stepRight}>
                                <a disabled={nextIsDisabled} aria-disabled={nextIsDisabled} className={styles.next} href="#"
                                    tabIndex={0}
                                    onClick = {this.nextSlideClicked}>BUTTONNEXTTEXT
                                </a>
                                </li>
                            </ul>
                        </nav>
                    </div>
               </div> :
               null;

};

private resetState(): void {
    const newState: ICarouselState = {
            position: 0,
            width: numSlides * 100,
            isActiveNext: true,
            isActivePrev: false,
            isActive: 0
        };

    if (this.state) {
        this.setState(newState);
    } else {
        this.state = newState;
    }
}

private nextSlideClicked: () => void = () => {
    if (this.state.position > min + move) {
        this.setState({
            position: this.state.position - move,
            width: numSlides * 100,
            isActiveNext: true,
            isActivePrev: true,
            isActive: Math.abs((this.state.position - move) / move)
        });
    } else if ((this.state as ICarouselState).position > min) {
        this.setState({
            position: this.state.position - move,
            width: numSlides * 100,
            isActiveNext: false,
            isActivePrev: true,
            isActive: Math.abs((this.state.position - move) / move)
        });
    }
};

private prevSlideClicked: () => void = () => {
    if (this.state.position < 0 - move) {
        this.setState({
            position: this.state.position + move,
            width: numSlides * 100,
            isActiveNext: true,
            isActivePrev: true,
            isActive: Math.abs((this.state.position + move) / move)
        });
    } else if (this.state.position < 0) {
        this.setState({
            position: this.state.position + move,
            width: numSlides * 100,
            isActiveNext: true,
            isActivePrev: false,
            isActive: Math.abs((this.state.position + move) / move)
        });
    }
};

private getCarouselName(): CarouselNames {
    return "name"
}

};

Thanks.

like image 771
Programmer Avatar asked Aug 02 '16 00:08

Programmer


2 Answers

I had the same problem. I set a distinct 'key' property on each instance and the problem went away.

like image 161
Benjamin Talisman Avatar answered Nov 15 '22 04:11

Benjamin Talisman


If you are using the same component for a different route (react-router) then you have to set key property for each route.

Keys help React identify which items have changed, are added, or are removed.

For this kind of situation where you want to use the same component multiple times, you have to set key property. Otherwise, each component will have the same state.

like image 34
Jaied Avatar answered Nov 15 '22 05:11

Jaied