Xtophe
Xtophe

Reputation: 2277

Showing / Hiding components on click based on current state in ReactJS

Disclaimer: I am new to ReactJS

I am trying to implement a dialog window to select a country/language at on the first page of my application.

The idea is the following:

My dialog box initially looks like this:

country and language selection

After clicking on the Vietnamese flag it should changes into this:

enter image description here

After clicking on the country flag, I want two buttons (divs) to appear on the right of the flag so that the user can choose a language. So I am trying to conditionally add the divs based on the current state corresponding to the selected language:

<div className="Country-flag-big" onClick={this.selectCountry("KH")} data-country={"KH"} />
{ this.state.countrySelected==="KH" ? <div className="Language-big" onClick={this.selectLocale} data-locale={"km-KH"} >ភាសាខ្មែរ</div> : null }
{ this.state.countrySelected==="KH" ? <div className="Language-big" onClick={this.selectLocale} data-locale={"en-KH"} >English</div> : null }

However, it does not work, there is an error when the dialog box opens, as if the onClick event was triggered already and creating a conflict:

Warning: setState(...): Cannot update during an existing state transition (such as within render or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to componentWillMount.

Here is the complete component code:

import React from 'react';
import ReactDOM from 'react-dom';
import './CountryFlag.css';

var Dialog = React.createClass({
    getInitialState: function () {
        return { countrySelected: "" };
    },

    close(){
        ReactDOM.unmountComponentAtNode(this.props.container);
    },

    componentWillUnmount() {
        document.body.removeChild(this.props.container); 
    },

    selectCountry(country) {
        console.log('this is c:', country);
        this.setState({countrySelected: country});
    },

    selectLocale() {
        console.log('this is:', this);
        ReactDOM.unmountComponentAtNode(this.props.container);
    },

    render(){
        return(
            <div className="Country-dialog-overlay">
                <div className="Country-dialog-inner">
                    <h2>Country > Language</h2>
                    <div className="Country-flag-big" onClick={this.selectCountry("KH")} data-country={"KH"} />
                    { this.state.countrySelected==="KH" ? <div className="Language-big" onClick={this.selectLocale} data-locale={"km-KH"} >ភាសាខ្មែរ</div> : null }
                    { this.state.countrySelected==="KH" ? <div className="Language-big" onClick={this.selectLocale} data-locale={"en-KH"} >English</div> : null }

                    <div className="Country-flag-big" onClick={this.selectCountry("LA")} data-country={"LA"} />
                    { this.state.countrySelected==="LA" ? <div className="Language-big" onClick={this.close} data-locale={"lo-LA"} >ພາສາລາວ</div> : null }
                    { this.state.countrySelected==="LA" ?<div className="Language-big" onClick={this.close} data-locale={"en-LA"} >English</div> : null }

                    <div className="Country-flag-big" onClick={this.selectCountry("MM")} data-country={"MM"} />
                    { this.state.countrySelected==="MM" ? <div className="Language-big" onClick={this.close} data-locale={"my-MM"} >မြန်မာ</div> : null }
                    { this.state.countrySelected==="MM" ? <div className="Language-big" onClick={this.close} data-locale={"en-MM"} >English</div> : null }

                    <div className="Country-flag-big" onClick={this.selectCountry("TH")} data-country={"TH"} />
                    { this.state.countrySelected==="TH" ? <div className="Language-big" onClick={this.close} data-locale={"th-TH"} >ภาษาไทย</div> : null }
                    { this.state.countrySelected==="TH" ? <div className="Language-big" onClick={this.close} data-locale={"en-TH"} >English</div> : null }

                    <div className="Country-flag-big" onClick={this.selectCountry("VN")} data-country={"VN"} />
                    { this.state.countrySelected==="VN" ? <div className="Language-big" onClick={this.close} data-locale={"vi-VN"} >Tiếng việt</div> : null }
                    { this.state.countrySelected==="VN" ? <div className="Language-big" onClick={this.close} data-locale={"en-VN"} >English</div> : null }
                </div>
            </div>
        );  
    }
});

var Trigger = () => {
    function showDialog() {
        var div = document.createElement('div');
        ReactDOM.render(
            <Dialog container={div}/>,
            document.body.appendChild(div)
        );
    }

    return (
        <div className="Country-flag" onClick={showDialog} data-country={"VN"} />
    );
};

class CountryFlag  extends React.Component {
    render() {
        return (
            <Trigger />
        );
    }
}

export default CountryFlag;

Any idea why I have this error?

Thanks!

Upvotes: 0

Views: 372

Answers (2)

glhrmv
glhrmv

Reputation: 1782

When you do

onClick={this.selectCountry("KH")}

You're actually calling the function, and not storing a reference to the click handler so that it only fires when clicked. You can either do

onClick={() => this.selectCountry("KH")}

or even better, make a bound function that passes in the country name, like so

onClick={this.selectCountry.bind(this, "KH")}

However, since you have data- attributes in those elements that you're clicking on, you can put just onClick={this.selectCountry} and in the selectCountry handler, you can rewrite it like so

selectCountry(e) {
  let country = e.currentTarget.dataset.country;
  // country will be "KH" for example
}

Upvotes: 1

Shubham Khatri
Shubham Khatri

Reputation: 281626

<div className="Country-flag-big" onClick={this.selectCountry("KH")} data-country={"KH"} /> statement causes the error.

It should be

 <div className="Country-flag-big" onClick={() => this.selectCountry("KH")} data-country={"KH"} />

at every place

The reason it did not work in your case is that onClick expects a function but with onClick={this.selectCountry("KH")} you are actually giving it a value retuned by selectCountry function. Since you are setting a state in selectCountry you render is called again and everytime render is called, selectCountry is evaluated to return the value to onClick. You need to bind the function in order the pass the value.

You render function will be

render(){
    return(
        <div className="Country-dialog-overlay">
            <div className="Country-dialog-inner">
                <h2>Country > Language</h2>
                <div className="Country-flag-big" onClick={() => this.selectCountry("KH")} data-country={"KH"} />
                { this.state.countrySelected==="KH" ? <div className="Language-big" onClick={this.selectLocale} data-locale={"km-KH"} >ភាសាខ្មែរ</div> : null }
                { this.state.countrySelected==="KH" ? <div className="Language-big" onClick={this.selectLocale} data-locale={"en-KH"} >English</div> : null }

                <div className="Country-flag-big" onClick={() => this.selectCountry("LA")} data-country={"LA"} />
                { this.state.countrySelected==="LA" ? <div className="Language-big" onClick={this.close} data-locale={"lo-LA"} >ພາສາລາວ</div> : null }
                { this.state.countrySelected==="LA" ?<div className="Language-big" onClick={this.close} data-locale={"en-LA"} >English</div> : null }

                <div className="Country-flag-big" onClick={() => this.selectCountry("MM")} data-country={"MM"} />
                { this.state.countrySelected==="MM" ? <div className="Language-big" onClick={this.close} data-locale={"my-MM"} >မြန်မာ</div> : null }
                { this.state.countrySelected==="MM" ? <div className="Language-big" onClick={this.close} data-locale={"en-MM"} >English</div> : null }

                <div className="Country-flag-big" onClick={() => this.selectCountry("TH")} data-country={"TH"} />
                { this.state.countrySelected==="TH" ? <div className="Language-big" onClick={this.close} data-locale={"th-TH"} >ภาษาไทย</div> : null }
                { this.state.countrySelected==="TH" ? <div className="Language-big" onClick={this.close} data-locale={"en-TH"} >English</div> : null }

                <div className="Country-flag-big" onClick={() => this.selectCountry("VN")} data-country={"VN"} />
                { this.state.countrySelected==="VN" ? <div className="Language-big" onClick={this.close} data-locale={"vi-VN"} >Tiếng việt</div> : null }
                { this.state.countrySelected==="VN" ? <div className="Language-big" onClick={this.close} data-locale={"en-VN"} >English</div> : null }
            </div>
        </div>
    );  
}

Upvotes: 0

Related Questions