others-How to solve 'Uncaught TypeError: this.props.onClick is not a function' in JavaScript?

1. Purpose

In this post, I would demo how to solve the following issue when trying to call a function from child component to parent component in react.js, but this problem is a common one in JavaScript world.

index.js:11 Uncaught TypeError: this.props.onClick is not a function
    at onClick (index.js:11)
    at HTMLUnknownElement.callCallback (react-dom.development.js:3945)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:3994)
    at invokeGuardedCallback (react-dom.development.js:4056)
    at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:4070)
    at executeDispatch (react-dom.development.js:8243)
    at processDispatchQueueItemsInOrder (react-dom.development.js:8275)
    at processDispatchQueue (react-dom.development.js:8288)
    at dispatchEventsForPlugins (react-dom.development.js:8299)
    at react-dom.development.js:8508
    at batchedEventUpdates$1 (react-dom.development.js:22396)
    at batchedEventUpdates (react-dom.development.js:3745)
    at dispatchEventForPluginEventSystem (react-dom.development.js:8507)
    at attemptToDispatchEvent (react-dom.development.js:6005)
    at dispatchEvent (react-dom.development.js:5924)
    at unstable_runWithPriority (scheduler.development.js:468)
    at runWithPriority$1 (react-dom.development.js:11276)
    at discreteUpdates$1 (react-dom.development.js:22413)
    at discreteUpdates (react-dom.development.js:3756)
    at dispatchDiscreteEvent (react-dom.development.js:5889)
onClick @ index.js:11
callCallback @ react-dom.development.js:3945
invokeGuardedCallbackDev @ react-dom.development.js:3994
invokeGuardedCallback @ react-dom.development.js:4056
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4070
executeDispatch @ react-dom.development.js:8243
processDispatchQueueItemsInOrder @ react-dom.development.js:8275
processDispatchQueue @ react-dom.development.js:8288
dispatchEventsForPlugins @ react-dom.development.js:8299
(anonymous) @ react-dom.development.js:8508
batchedEventUpdates$1 @ react-dom.development.js:22396
batchedEventUpdates @ react-dom.development.js:3745
dispatchEventForPluginEventSystem @ react-dom.development.js:8507
attemptToDispatchEvent @ react-dom.development.js:6005
dispatchEvent @ react-dom.development.js:5924
unstable_runWithPriority @ scheduler.development.js:468
runWithPriority$1 @ react-dom.development.js:11276
discreteUpdates$1 @ react-dom.development.js:22413
discreteUpdates @ react-dom.development.js:3756
dispatchDiscreteEvent @ react-dom.development.js:5889
react-dom.development.js:4091 Uncaught TypeError: this.props.onClick is not a function
    at onClick (index.js:11)
    at HTMLUnknownElement.callCallback (react-dom.development.js:3945)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:3994)
    at invokeGuardedCallback (react-dom.development.js:4056)
    at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:4070)
    at executeDispatch (react-dom.development.js:8243)
    at processDispatchQueueItemsInOrder (react-dom.development.js:8275)
    at processDispatchQueue (react-dom.development.js:8288)
    at dispatchEventsForPlugins (react-dom.development.js:8299)
    at react-dom.development.js:8508
    at batchedEventUpdates$1 (react-dom.development.js:22396)
    at batchedEventUpdates (react-dom.development.js:3745)
    at dispatchEventForPluginEventSystem (react-dom.development.js:8507)
    at attemptToDispatchEvent (react-dom.development.js:6005)
    at dispatchEvent (react-dom.development.js:5924)
    at unstable_runWithPriority (scheduler.development.js:468)
    at runWithPriority$1 (react-dom.development.js:11276)
    at discreteUpdates$1 (react-dom.development.js:22413)
    at discreteUpdates (react-dom.development.js:3756)
    at dispatchDiscreteEvent (react-dom.development.js:5889)
onClick @ index.js:11
callCallback @ react-dom.development.js:3945
invokeGuardedCallbackDev @ react-dom.development.js:3994
invokeGuardedCallback @ react-dom.development.js:4056
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:4070
executeDispatch @ react-dom.development.js:8243
processDispatchQueueItemsInOrder @ react-dom.development.js:8275
processDispatchQueue @ react-dom.development.js:8288
dispatchEventsForPlugins @ react-dom.development.js:8299
(anonymous) @ react-dom.development.js:8508
batchedEventUpdates$1 @ react-dom.development.js:22396
batchedEventUpdates @ react-dom.development.js:3745
dispatchEventForPluginEventSystem @ react-dom.development.js:8507
attemptToDispatchEvent @ react-dom.development.js:6005
dispatchEvent @ react-dom.development.js:5924
unstable_runWithPriority @ scheduler.development.js:468
runWithPriority$1 @ react-dom.development.js:11276
discreteUpdates$1 @ react-dom.development.js:22413
discreteUpdates @ react-dom.development.js:3756
dispatchDiscreteEvent @ react-dom.development.js:5889

The core error message is:

index.js:11 Uncaught TypeError: this.props.onClick is not a function
react-dom.development.js:4091 Uncaught TypeError: this.props.onClick is not a function

And this error is shown on page:

image-20211129120507818

2. Environment

  • npm and node version:
➜  ~ npm version
{
  npm: '8.1.2',
  node: '17.1.0',
  v8: '9.5.172.25-node.13',
  uv: '1.42.0',
  zlib: '1.2.11',
  brotli: '1.0.9',
  ares: '1.18.1',
  modules: '102',
  nghttp2: '1.45.1',
  napi: '8',
  llhttp: '6.0.4',
  openssl: '3.0.0+quic',
  cldr: '39.0',
  icu: '69.1',
  tz: '2021a',
  unicode: '13.0',
  ngtcp2: '0.1.0-DEV',
  nghttp3: '0.1.0-DEV'
}

3. The code and the solution

3.1 The code that cause the problem

I am writing a tic-tac-toe game by following the tutorial, and when it comes to call from child to parent component, where we need to pass a function from parent to child , the error occurred.

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";

class Square extends React.Component {
  render() {
    return (
      <button
        className="square"
        onClick={() => {
          this.props.onClick();
        }}
      >
        {this.props.value}
      </button>
    );
  }
}

class Board extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      squares: Array(9).fill(null),
      lastState: null,
    };
  }
  onSquareClicked = (i) => {
    console.log("square clicked " + i);
    if (this.state.squares[i] == null) {
      if (this.state.lastState == null) {
        this.state.squares[i] = "X";
        this.state.lastState = "X";
      } else if (this.state.lastState == "X") {
        this.state.squares[i] = "O";
        this.state.lastState = "O";
      }
      //this.renderSquare(i);
    }
  };
  renderSquare(i) {
    return (
      <Square
        value={i}
        theState={this.state.squares[i]}
        onClick={this.onSquareClicked(i)}
      />
    );
  }

  render() {
    const status = "Next player: X";

    return (
      <div>
        <div className="status">{status}</div>
        <div className="board-row">
          {this.renderSquare(0)}
          {this.renderSquare(1)}
          {this.renderSquare(2)}
        </div>
        <div className="board-row">
          {this.renderSquare(3)}
          {this.renderSquare(4)}
          {this.renderSquare(5)}
        </div>
        <div className="board-row">
          {this.renderSquare(6)}
          {this.renderSquare(7)}
          {this.renderSquare(8)}
        </div>
      </div>
    );
  }
}


The program can be illustrated as follows:

image-20211129164704553

The error occurred when user click any of the squares:

      <button
        className="square"
        onClick={() => {
          this.props.onClick();
        }}
      >
        {this.props.value}
      </button>

which would call the function:

() => {
          this.props.onClick();
        }

and the this.props.onClick is passed from parent component as follows:

<Square
        value={i}
        theState={this.state.squares[i]}
        onClick={this.onSquareClicked(i)}
      />

You can see that we passed a function to onClick of square component, why did the error happen?

3.2 The solution to this problem

The solution is easy, just change the functions in Board component as follows:

  onSquareClicked(i) {
    console.log("square clicked " + i);
  }
  renderSquare(i) {
    return (
      <Square
        value={i}
        theState={this.state.squares[i]}
        onClick={() => {
          this.onSquareClicked(i);
        }}
      />
    );
  }

First ,we need to turn onSquareClicked into a normal function, which has a single parameter to track which square is clicked and action on the event.

Second, we change the onClick property to use an arrow function ,which has no parameters and just call the onSquareClicked.

3.3 Why did this happen and why the solution is working?

This error happened because we are calling the function instead of passing the reference of the function to child.

According to this document, the error TypeError: "x" is not a function happens when:

It attempted to call a value from a function, but the value is not actually a function. Some code expects you to provide a function, but that didn’t happen.

Maybe there is a typo in the function name? Maybe the object you are calling the method on does not have this function? For example, JavaScript Objects have no map function, but the JavaScript Array object does.

There are many built-in functions in need of a (callback) function. You will have to provide a function in order to have these methods working properly:

The solution is working because we need to pass a function’s reference to child ,but we passed a function result to child, which is not function by itself. We use arrow function because the arrow function would return a function reference instead of calling the function.

4. Summary

In this post, I demonstrated how to solve the ‘TypeError: “x” is not a function’ error when trying to pass function to components in react.js, the key point is to pass the reference , you can achieve this goal by using arrow functions . That’s it, thanks for your reading.