26

I'm working on breaking up a little react app into smaller components. Before separating code everything worked as planned. I now am trying to call a function onChange that calls a function and then that calls a function as a prop. I am binding the function like this this.updateInput = this.updateInput.bind(this); but I still cannot figure out what I am missing. I tried a recent post on here (React : Pass function to child component) but the error still remains. Any help is great.

Here is the code I am working with:

class Weather extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      city: '',
      details: []
    };

    this.updateInputValue = this.updateInputValue.bind(this);
  }

  updateInputValue(e) {
    this.setState({
      city: e.target.value
    });
    console.log('hit')
  }

  render() {
    return (
      <div className={style.container + ' ' + style.bodyText}>
        <WeatherForm
          updateInput={this.updateInputValue}
        />
      </div>
    );
  }
}


class WeatherForm extends React.Component {
  constructor(props) {
    super(props);
    this.updateInput = this.updateInput.bind(this); 
  }

  updateInput(e) {
    this.props.updateInputValue(e);
  }

  render() {
    return (
      <div className={style.weatherForm}>
        <form action='/' method='GET'>
          <input ref='city' value={this.props.inputValue} onChange={e => this.updateInput(e)} type='text' placeholder='Search city' />
        </form>
      </div>
    );
  }
}

So when I type one character in the input, instead of the console logging hit, it says Uncaught TypeError: this.props.updateInputValue is not a function. What am I missing here?

justDan
  • 2,302
  • 5
  • 20
  • 29
  • 1
    Perhaps it should be just `this.updateInputValue(e)` and not `this.props.updateInputValue(e)`. – Pointy Jun 27 '18 at 15:08
  • 1
    Simple, first determine what `this.props` is using `console.log`. Once that's done you'll see your mistake by yourself. – Vivick Jun 27 '18 at 15:10

3 Answers3

10

It should be

<WeatherForm
          updateInputValue={this.updateInputValue}
        />

Common related problem:

The same "is not a function" error can also be caused by mis-using the props, as shown in this question

degr
  • 1,559
  • 1
  • 19
  • 37
5

Your child component only has the prop of updateInput as a method and you're calling this.props.updateInputValue() in child component. Try to call them the same names.

You're also calling this.props.inputValue in the child component when you're not passing inputValue into your child component as a props.

What I would do to simplify the code and possible avoid mistakes like this in the future is to directly call this.props.updateInputValue in onChange event like this:onChange={e => this.props.updateInputValue(e)} You then save the work of binding another component method in constructor. It'll also make your unit testing easier but that's another discussion.

mxdi9i7
  • 677
  • 4
  • 13
  • 1
    Thanks for the response! The `this.props.inputValue` is the next problem up on the task list. Thanks for the explanation there also. At times the `prop` stuff makes me cross-eyed. – justDan Jun 27 '18 at 15:15
0

If you are using React Hooks than this can be helpful answer. note: I am using react 18

If your set is throwing this error: enter image description here

Solution:

You must not be defining your setTitle properly, or you must be restructing the state in wrong way.

  • const {title, setTitle} = useState(""); is wrong
  • const [title, setTitle] = useState(""); is correct

Code Sample:

import React, {useState} from "react";
import axios from "axios";


export default () => {
    const {title, setTitle} = useState("");

    const onSubmit = async (event) => {
        event.preventDefault(); 

        const createdId = await axios.post("http://localhost:4000/posts", {
            "title": title
        });

        setTitle("");
    };

    const handleTextChange = (event) => {        
        setTitle(event.target.value)
    }

    return <div>
        <form>
            <div className="form-group">
                <label> Title </label>
                <input value={title} onChange={handleTextChange} className="form-control"></input>
            </div>
            <div className="btn btn-primary" onSubmit={onSubmit}>
                Submit
            </div>
        </form>
    </div>;
};
KushalSeth
  • 3,265
  • 1
  • 26
  • 29