Simon Leigh
Simon Leigh

Reputation: 53

React/Redux argument becomes undefined after passed to action

I have a simple search bar that has an onChange method to search/filter data.

class ItemSearch extends React.Component {

constructor(){
  super();
  this.handleOnChange = this.handleOnChange.bind(this);
}

handleOnChange(e){
  const searchTerm = this.search.value;
  console.log(searchTerm);
  this.props.fetchSearch(searchTerm);
}

render() {
  return (
    <div>
      <form>
        <input type='text' ref={(input) => {this.search = input}} onChange={this.handleOnChange}></input>
      </form>
      <div>
        {this.props.data.map((item, i) => {
          return <ListItem
            key={i}
            item={item}
          />
        })}
      </div>
    </div>
  )
}
}

Logging out the search term gives me the correct value. However, after it is passed to the redux action creator it becomes undefined. My action is pretty simple, something like this.

export default function fetchSearch(value){
  console.log(value);
  return {
    type: 'FETCH_SEARCH',
    payload: value
  }
}

In this log it has become undefined. I assume it has something do to with it being out of scope, but without passing arguments to action creators, there is no way of lifting state up to the store from forms anyway. I have seen this exact thing working in many tutorials and posts so I am at a bit of a loss, although it is probably something silly I missed.

Thanks.

Upvotes: 0

Views: 1762

Answers (2)

Simon Leigh
Simon Leigh

Reputation: 53

I just forgot to update the mapDipatchToProps in the container. Once I did that it works fine. Thanks all!

Upvotes: 2

Ravindra Ranwala
Ravindra Ranwala

Reputation: 21124

Yes you have made a mistake here. Firstly you have to use redux form to get this thing done. There you have to connect this with the reducer or store like below.

import React, { Component } from 'react';
import { reduxForm } from 'redux-form';
import { createTimer } from '../actions/index';

class TimerNew extends Component {

onSubmit(props){
  this.props.createTimer(props);
}

  render() {
  const { fields: { hours, minutes, seconds, label }, handleSubmit } = this.props;
  return (
    <form onSubmit={handleSubmit(this.props.createTimer)}>
      <h5>Create A New Timer</h5>
      <div className={`form-group ${hours.touched && hours.invalid ? 'has-danger' : ''}`}>
        <label>Hours</label>
        <input type="text" className="form-control" {...hours} />
        <div className="text-help">
          {hours.touched ? hours.error : ''}
        </div>
      </div>
      <div className={`form-group ${minutes.touched && minutes.invalid ? 'has-danger' : ''}`}>
        <label>Minutes</label>
        <input type="text" className="form-control" {...minutes} />
        <div className="text-help">
          {minutes.touched ? minutes.error : ''}
        </div>
      </div>
      <div className={`form-group ${seconds.touched && seconds.invalid ? 'has-danger' : ''}`}>
        <label>Seconds</label>
        <input type="text" className="form-control" {...seconds} />
        <div className="text-help">
          {seconds.touched ? seconds.error : ''}
        </div>
      </div>
      <div className={`form-group ${label.touched && label.invalid ? 'has-danger' : ''}`}>
        <label>Label</label>
        <input type="text" className="form-control" {...label} />
        <div className="text-help">
          {label.touched ? label.error : ''}
        </div>
      </div>
      <button type="submit" className="btn btn-primary">Submit</button>
    </form>
  );
  }
}

function validate(values) {
  const errors = {};

  if (!values.hours) {
    errors.title = 'Enter hours';
  }
  if (!values.minutes) {
    errors.categories = 'Enter minutes';
  }
  if (!values.seconds) {
    errors.content = 'Enter seconds';
  }
  if (!values.label) {
    errors.content = 'Enter label';
  }
  return errors;
}

// connect: first argument is mapStateToProps, 2nd is mapDispatchToProps
// reduxForm: 1st is form config, 2nd is mapStateToProps, 3rd is mapDispatchToProps
export default reduxForm({
  form: 'TimerNewForm',
  fields: ['hours', 'minutes', 'seconds', 'label'],
  validate
}, null, { createTimer })(TimerNew);

Here you have to wrap your form with the call to the reduxForm helper and pass in the action creator in my case it is createTimer. Also note that the code may differ based on the redux-forms version you are using. Here I am using 4.3.*. You may check out the redux-forms documentation here for further details. Hope this helps. Happy coding.

Upvotes: 0

Related Questions