Search code examples
reactjsreactjs-fluxredux

Dispatch isn't called when I use bindActionCreators


I'm able to get an input to update my redux store onChange if I explicitly write out the dispatch function. Why does it stop working when I try to use bindActionCreators()?

not using bindActionCreators (this works)

@connect(
  state => ({}),
  dispatch => {
    return {
      onSearchChange: (term) => {
        dispatch(search(term));
      }
    };
  }
)

export default class SearchForm extends Component {
  render() {
    return (
      <input type="text" onChange={(event) => onSearchChange(event.target.value)} />
    );
  }
}

using bindActionCreators (this does not work. It never dispatches the action)

@connect(
  state => ({ categories: state.categories.data }),
  dispatch => bindActionCreators({search}, dispatch)
);

export default class SearchForm extends Component {
  render() {
    return (
      <input type="text" onChange={(event) => search(event.target.value)} />
    );
  }
}

Solution

  • There are a couple issues here that seem to be syntactical and unrelated to Redux; they could be copy-paste errors, or actual issues:

    1. Your second example contains a syntax error; there should not be a semicolon at the end of the decorator:

      repl: Leading decorators must be attached to a class declaration (4:1)
        2 |   state => ({ categories: state.categories.data }),
        3 |   dispatch => bindActionCreators({search}, dispatch)
        4 | );
          |  ^
      
    2. The functions you're calling in the event handler (in both examples) don't seem to be defined; for them to work as written, you'd need to extract the function from this.props:

      export default class SearchForm extends Component {
        render() {
          const { search } = this.props;
          return (
            <input type="text" onChange={(event) => search(event.target.value)} />
          );
        }
      }
      

      If the examples are as written here in your code, I would expect the first example to fail unless there was an onSearchChange function declared in scope.

    As a shortcut, connect can accept a simple object as a second argument, and it will assume each value on the object is an action creator for it to bind to:

    @connect(
      state => ({ categories: state.categories.data }),
      { search }
    )
    export default class SearchForm extends Component {
    

    [Edit]

    Since you import search via

    import {search} from 'redux/modules/repo-search';
    

    you can import it instead with an alias

    import { search as searchActionCreator } from 'redux/modules/repo-search';
    

    If you do this, then connect needs to know the value you really want to use for the prop:

    @connect(
      state => ({ categories: state.categories.data }),
      {search: searchActionCreator}
    )
    export default class SearchForm extends Component {
      render() {
        const { search } = this.props;
        return (
          <input type="text" onChange={(event) => search(event.target.value)} />
        );
      }
    }
    

    Alternatively, simply use a different variable name, or the path to the function in this.props, inside render:

    return (
      <input type="text" onChange={(event) => this.props.search(event.target.value)} />
    );