3

I know this question is asked a lot because I have done the first two pages of Google and I have searched about it on SO but I didn't found solution for me and I have no idea why i got this error.

So here is my parent component

class App extends Component {
    state = { lang: language }

    constructor(props) {
        super(props)
        this.handleLanguage = this.handleLanguage.bind(this)
      }

      handleLanguage(langValue){
        this.setState({lang: langValue});
    }

    render() {
        return (
            <IntlProvider locale={this.lang} messages={messages}>
                <div className="App">
                    <div className="App-content">
                        <React.Fragment>
                            <div className="menu">
                                <Navbar handleLanguage={this.handleLanguage}></Navbar>
                            </div>
                            <Main />
                        </React.Fragment>
                    </div>
                </div>
            </IntlProvider>

        );
    }
}

export default (App);

and here is my children component

export class Navbar extends React.Component {
    constructor() {
        super();
        this.langChange = this.langChange.bind(this)
    }

    langChange(value){
        var lang = value;
        this.props.handleLanguage(lang);            
    }


    render() {
        return (
            <nav className="navbar navbar-expand-lg nav-bar-bg">
                <a href="/">
                    <img src={Logo_horizontal_flat} className="logo-horizontal-flat"></img>
                </a>
                <div className="collapse navbar-collapse" id="navbarSupportedContent">
                    <div className="navbar-nav">
                        <a className="nav-item nav-link" onClick={() => this.langChange("fr")}><img className="flag" src={flag_fr}></img></a>
                        <a className="nav-item nav-link" onClick={() => this.langChange("en")}><img className="flag" src={flag_us}></img></a>
                    </div>
                </div>
            </nav>
        )
    }
}

I got this error

× TypeError: this.props.handleLanguage is not a function

I'm trying to pass a data to a parent from his child with following this issue: How to pass data from child component to its parent in ReactJS?

But I have no idea why I still got this error, I even try to Type my props with PropTypes like this

Navbar.propTypes = {
    handleLanguage: PropTypes.func
};

but it didn't change anything ...

EDIT

Actually it's working when I remove my Main components which is a component with my routes

export class Main extends React.Component {

    render (){
        return (
            <Switch>
                <Route exact path="/" component={Home}></Route>
                <Route path='/signup' component={RegisterPart2} ></Route>
                <Route path='/signup1' component={RegisterPart1} ></Route>
                <Route path='/signup2' component={RegisterPart3} ></Route>
                <Route path='/login' component={Login} ></Route>
                <Route path='/profile' component={Profile} ></Route>
                <Route path='/information' component={Information} ></Route>                
                <Route path='/account' component={Account} ></Route> 
                <Route path='/address' component={Adresses} ></Route>                
                <Route path='/addadress' component={Addadresses} ></Route>                
                <Route path='/countries' component={Countries} ></Route>                
            </Switch>
        );
    }
}

I have no idea how this component can affected it, any idea ?

EDIT 2

Finally I got the answer, it's because in my Home component I called the Navbar component again.

Thanks for your help everyone

Thank in advance for your help

Thebeginner
  • 143
  • 3
  • 15

1 Answers1

0

I assume what you are looking here is to pass state from a child to props.Assuming you want to keep the name of the function of the child component as follows: onClick={() => this.langChange("fr")}, then on your parent component you need to change:

 handleLanguage(langValue){
        this.setState({lang: langValue});
    }

with:

 langChange(langValue){
        this.setState({lang: langValue});
    }

and <Navbar handleLanguage={langValue=>this.langChange(langValue)}></Navbar>

A few pointers to improve your code. You are using state and not this.state. If you decide to use a constructor and super with props you have to do something like that:

 constructor(props){
    super(props);
    this.state={"your state inside here"}
// bind your functions
}

The way you are using state i.e state = { lang: language } you can drop the constructor and super and autobind with arrow functions

No need to use <React.Fragment> in your case. If you absolutely have to use it, use the shorthand syntax of <></> that doesn't even require to import the Fragment. Only use <React.Fragment> when you need to assign a property to the fragment such as a key for an iteration.

Finally and most importantly, I don't see the reason to use state within your navbar. Your App should be perfectly fine to handle your app's state, unless it grows and then you might consider using Redux.

KT-mongo
  • 2,044
  • 4
  • 18
  • 28
  • Why should renaming the function make a difference? – Felix Kling Dec 03 '18 at 21:51
  • It's not about renaming the function that makes the difference, it's about where the function points to with the onclick event handler from the navbar component. How you structured your code you can't lift state up – KT-mongo Dec 03 '18 at 21:59
  • It's not my code. I'm just pointing out that there isn't really a difference between your suggested solution and what the OP has wrt the event handler. *"it's about where the function points to with the onclick event handler from the navbar component."* All you did is 1) rename the function and b) introduce another intermediary function to call the handler. Here is a simplified example of what I mean: The OP has `function foo() {}; bar(foo);` and you changed that to `function foo2() {}; function anotherFunc() { foo2(); }; bar(anotherFunc);`. But both code snippets behave exactly the same. – Felix Kling Dec 03 '18 at 22:00
  • I got thrown of by your code. As I mentioned above I thought you were trying to lift state up. I saw a constructor and a class for your Navbar. Again this is why I point you back about your code. Why use a class and a constructor if you don't use neither lifecycle hooks nor state? Anyway, you are using 2 functions. So for your navbar keep the function as it is `onClick={() => this.langChange("fr")}` and remove the `langChange(value){ var lang = value; this.props.handleLanguage(lang); }` on your app component ... – KT-mongo Dec 03 '18 at 22:25
  • change this ` handleLanguage(langValue){ this.setState({lang: langValue}); }` with ` langChange(langValue){ this.setState({lang: langValue}); }` and pass it on the navbar component as property: `` – KT-mongo Dec 03 '18 at 22:27
  • 1
    Again, it's not my code. It's not my question. I'm just pointing out that your suggested change wouldn't make a difference. *"change this ... with ...."* now you are just renaming the method, which I said before, won't make a difference. Keep in mind the error the OP is getting: *"TypeError: this.props.handleLanguage is not a function"* . Renaming the function won't make that error go away. – Felix Kling Dec 03 '18 at 22:34
  • have you tried my suggestion? I didn't say to rename the function only. You are using 2 functions where 1 is needed, so no this isn't about renaming the function. If you have tried exactly my recommendation from my 2 responsnes and it didn't work, send a sandbox with the code and I will have it working – KT-mongo Dec 03 '18 at 22:40
  • @Kleo Thank you for your help, I tried your changed but the error is still same, here is a sandbox with my code and your change https://codesandbox.io/s/qx90zq4mvj – Thebeginner Dec 04 '18 at 01:16
  • I have edited my first message. I now know why it work on sandbox and not on my actual code. But I still don't know why it does that – Thebeginner Dec 04 '18 at 01:45