0

I am developing an application in Reactjs, utilizing the Redux architecture. The application is using a third-party api that gets called when I submit a city into the search bar. In testing it, I get a console error which reads:

Uncaught TypeError: this.props.fetchWeather is not a function

I am unclear as to why React tells me that fetchWeather is not a function when it exists as a function here on src/actions/index.js:

import axios from 'axios';

const API_KEY = 'spj3q-9huq]-hq -9hq 0rgjeth9e';
const ROOT_URL = `http://api.openweathermap.org/data/2.5/forecast?appid=${API_KEY}`;

export const FETCH_WEATHER = 'FETCH_WEATHER';

export function fetchWeather(city) {
  const url = `${ROOT_URL}&q=${city},us`;
  const request = axios.get(url);

  return {
    type: FETCH_WEATHER,
    // optional property
    // promise passed in
    payload: request
  };
}

this.props.fetchWeather(this.state.term); is what I need to fetch the weather data and this line of code exists in container/search_bar.js:

import React, {Component} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {fetchWeather} from '../actions/index';

export default class SearchBar extends Component {
  constructor(props) {
    super(props);

    this.state = {term: ''};

    this.onInputChange = this.onInputChange.bind(this);
    // always need to bind this
    this.onFormSubmit = this.onFormSubmit.bind(this);
  }

  onInputChange(event) {
    this.setState({term: event.target.value});
  }
  // callback
  onFormSubmit(event) {
    event.preventDefault();

    // We need to go fetch weather data
    this.props.fetchWeather(this.state.term);
    // clear out the search input
    this.setState({term:''});
  }

  render() {
    return (
      <form onSubmit={this.onFormSubmit} className="input-group">
        <input
          placeholder="Get a five day forecast in your favorite cities"
          className="form-control"
          value={this.state.term}
          onChange={this.onInputChange}
        />
        <span className="input-group-btn">
          <button type="submit" className="btn btn-secondary">Submit</button>
        </span>
      </form>
    )
  }
}

function mapDispatchToProps(dispatch) {
  // makes sure this flows down into the middleware
  return bindActionCreators({fetchWeather}, dispatch);
}

connect(null, mapDispatchToProps)(SearchBar);
  • Stephen Grider's course? – Gerardo Aug 18 '17 at 00:52
  • Remove `this.props.`, that function is not a prop, but just a function in file scope. – Serge Seredenko Aug 18 '17 at 00:52
  • @Gerardo, yes Grider's course and appears that Serge is correct and Grider is incorrect. –  Aug 18 '17 at 00:57
  • Stephen is correct, you can check the code [here](https://github.com/StephenGrider/ReduxCasts/blob/master/weather/src/containers/search_bar.js) – Gerardo Aug 18 '17 at 00:58
  • @Gerardo, you are right. After checking the code I noticed that I had export default for class of SearchBar, which explains another error I was getting earlier that I could not implement export default twice. I thought it was referring to app.js file. So now I can add export default to connect as Doug proposed. –  Aug 18 '17 at 01:06
  • @Gerardo, you want to post it as an answer? –  Aug 18 '17 at 01:07
  • Doug already answered. – Gerardo Aug 18 '17 at 01:14

1 Answers1

1

You need to export the redux component, not the react component

export default connect(null, mapDispatchToProps)(SearchBar);

Doug
  • 14,387
  • 17
  • 74
  • 104
  • Doug, my understanding is that In React you cannot export default twice. If we have it in app.js we cannot do it again in search_bar.js. I tried it and received this error: bundle.js:22526 Uncaught Error: Cannot find module "../container/search_bar" –  Aug 18 '17 at 01:01