user3348410
user3348410

Reputation: 2833

React onClick function triggering itself at mount

I have a component that contains a basic onClick function.

The function is called when the component is rendering (without any click), why is it happening?

import React, { Component } from "react";
class Some extends Component {
  constructor(props) {
    super(props);
  }

  someFunc = (message) => {
    console.log(message)
  }


  render() {
    return (
       <p onClick={this.someFunc('hello')}>test</p>
     )
  }
}

Upvotes: 0

Views: 1423

Answers (4)

Joey Gough
Joey Gough

Reputation: 3103

in React you need to pass unexecuted functions, so either

onClick = {this.someFunction}

or if you need to pass an argument

onClick = {() => this.someFunction('argument')}

Upvotes: 4

typekev
typekev

Reputation: 633

tl;dr: You are invoking this.someFunc('hello') when you render your class, not when you call your onClick property. To fix it, you should use an arrow function, as so:

<p onClick={() => this.someFunc('hello')}>test</p>

Now if you want to know why this happens, let me clarify what you are doing.

import React, { Component } from "react";

class Some extends Component {
  constructor(props) {
    super(props);
  }

  // You define a class method that when called will in turn call the
  // console.log method, passing message as your argument.
  // message will equal 'hello' in your example.
  someFunc = (message) => {
    console.log(message)
  }

  // You define a render method of your class, react will 
  // automatically call this method on render.
  render() {

  // Your render method (which again is called automatically) will return
  // <p onClick={this.someFunc('hello')}>test</p>
  // let's see what operations you are performing in this JSX return.
    return (
       // You first define a paragraph html element to be rendered.
       // You then give your element an attribute called onClick.
       // But oh no! You are assigning onClick with the value of: 
       // this.someFunc('hello')
       //
       // That is not good, as what you are in effect saying is:
       // please call the method this.someFunc and pass a single argument: 'hello'
       // then assign the return of that method call to my property named onClick.
       // Therefore, every time you render this class, you are asking
       // javascript to call this function and get its value (which is undefined).
       // So while you think onClick is a function, it is not! it is only a value. 
       // A value which you are asking JavaScript to get for you on each render.
       // This is because in JS, when you write functionName(), 
       // you are literally calling the function at that moment.
       // See https://www.w3schools.com/js/js_function_invocation.asp
       <p onClick={this.someFunc('hello')}>test</p>

       // What you want to do instead is assign your onClick property
       // a function! Not a value! 
       // You want to write, "When I click here, do: this.someFunc('hello')"
       // to do that, you have some options, but the end goal will be the same
       // What you need to do is assign onClick a value, which when called (onClick)
       // will trigger your function! For instance:
       // onClick={() => this.someFunc('hello')}
       // Above we say "on each render, assign the onClick property a value which IS a function!"
       // This is, an unnamed arrow function!
       // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
       // Notice how we have defined an unnamed function that wraps our
       // this.someFunc('hello') and we have NOT
       // immediately called it (no parentheses following the wrapper function)
       // # outer function \() => #inner function \functionName()\ \ <-- No trailing parentheses.
       // Therefore, now the only way to execute your method named
       // this.someFunc('hello') is by calling its wrapper function.
       // And the only way to call that unnamed wrapper function?
       // By invoking your onClick property of your p element.
     )
  }
}

Upvotes: 0

dkrx81
dkrx81

Reputation: 63

The reason is because you write

<p onClick={this.someFunc('hello')}>test</p>

instead of

<p onClick={this.someFunc}>test</p>.

If you put there the () the function will be called right on rendering, else only if clicked.

Try this arrow function

<p onClick={() => this.someFunc('hello')}>test</p>

Not tested, but should work correctly this way.

Upvotes: 0

Alireza HI
Alireza HI

Reputation: 1933

You don't have to append your function like that. You just need to call it by other ways:

<p onClick={() => this.someFunc('hello')}>test</p>

By using this syntax you can call it by params.

But your first solution was just passing the function

If your function had no argument to pass you could just pass the function like below:

<p onClick={this.someFunc}>test</p>

Because you need to pass some arguments the first one which I mentioned will be your desired one.

You can read their document for further details: React Handling Events

Upvotes: 3

Related Questions