„wysyłka” nie jest funkcją, gdy argument do mapToDispatchToProps () w Redux

125

Jestem początkującym użytkownikiem języka javascript / redux / react, budującym małą aplikację za pomocą Redux, React-Redux i React. Z jakiegoś powodu, gdy używam funkcji mapDispatchToProps w tandemie z connect (wiązanie react-redux), otrzymuję TypeError wskazujący, że wysyłanie nie jest funkcją, gdy próbuję wykonać wynikową właściwość. Kiedy jednak wywołuję dispatch jako prop (zobacz funkcję setAddr w dostarczonym kodzie), to działa.

Jestem ciekawy, dlaczego tak jest, w przykładowej aplikacji TODO w dokumentach redux metoda mapDispatchToProps jest konfigurowana w ten sam sposób. Kiedy I console.log (dispatch) wewnątrz funkcji, mówi, że wysyłka jest obiektem typu. Mógłbym nadal korzystać z wysyłki w ten sposób, ale czułbym się lepiej, wiedząc, dlaczego tak się dzieje, zanim będę kontynuować dalszą pracę z reduxem. Do kompilacji używam WebPacka z programami ładującymi Babel.

Mój kod:

import React, { PropTypes, Component } from 'react';
import { connect } from 'react-redux';
import { setAddresses } from '../actions.js';
import GeoCode from './geoCode.js';
import FlatButton from 'material-ui/lib/flat-button';

const Start = React.createClass({
    propTypes: {
        onSubmit: PropTypes.func.isRequired
    },

    setAddr: function(){
        this.props.dispatch(
            setAddresses({
                pickup: this.refs.pickup.state.address,
                dropoff: this.refs.dropoff.state.address
            })
        )   

    },

    render: function() {
        return (
            <div>
                <div className="row">
                    <div className="col-xs-6">
                        <GeoCode ref='pickup' />
                    </div>
                    <div className="col-xs-6">
                        <GeoCode ref='dropoff' />
                    </div>
                </div>
                <div className="row">
                    <div className="col-xs-6">
                        <FlatButton 
                            label='Does Not Work'
                            onClick={this.props.onSubmit({
                                pickup: this.refs.pickup.state.address,
                                dropoff: this.refs.dropoff.state.address
                            })} 
                            />
                    </div>
                    <div className="col-xs-6">
                        <FlatButton 
                            label='Works'
                            onClick={this.setAddr} 
                            />
                    </div>
                </div>
            </div>
        );
    }
})

const mapDispatchToProps = (dispatch) => {
    return {
        onSubmit: (data) => {
            dispatch(setAddresses(data))
        }
    }
}

const StartContainer = connect(mapDispatchToProps)(Start)

export default StartContainer

Twoje zdrowie.

kalać
źródło
Miałem ten problem i to pomogło mi go rozwiązać
Alex W

Odpowiedzi:

249

Jeśli chcesz użyć mapDispatchToPropsbez mapStateToPropstylko nullpierwszego argumentu.

export default connect(null, mapDispatchToProps)(Start)

inostia
źródło
4
To jest to, czego szukałem. Teraz wiem, czy chcę po prostu wysłać kilka działań.
Emperor Krauser
To jest dokładnie to, czego szukałem. Dzięki za idealne rozwiązanie. A co, jeśli nie musimy używać mapDispatchToProps w żadnym z naszych komponentów? Czy to ten sam sposób, w jaki musimy sobie poradzić z tym scenariuszem?
Arun Ramachandran
1
Jeśli nie potrzebujesz mapDispatchToProps, po prostu nie dodawaj tego argumentu do connect:connect(mapStateToProps)(MyComponent)
inostia
107

Brakuje tylko pierwszego argumentu do connect, czyli mapStateToPropsmetody. Fragment aplikacji Redux todo:

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)
Brandon
źródło
3
czy użycie tej metody jest obowiązkowe? Ta metoda po prostu łapie stan, jeśli nie potrzebujemy tej metody?
Muneem Habib
6
@MuneemHabib zobacz odpowiedź inostii na temat tego, jak nie dostarczać tej metody, jeśli jej nie potrzebujesz
Brandon
21

Posługiwać się

const StartContainer = connect(null, mapDispatchToProps)(Start) 

zamiast

const StartContainer = connect(mapDispatchToProps)(Start)
Ann
źródło
6

Rozwiązałem to, zamieniając argumenty, których używałem

export default connect(mapDispatchToProps, mapStateToProps)(Checkbox)

co jest złe. To mapStateToPropsmusi być pierwszym argumentem:

export default connect(mapStateToProps, mapDispatchToProps)(Checkbox)

Teraz wydaje się to oczywiste, ale może komuś pomóc.

Amit Mittal
źródło
3

Potrzebowałem przykładu, React.Componentwięc zamieszczam go:

import React from 'react';
import * as Redux from 'react-redux';

class NavigationHeader extends React.Component {

}

const mapStateToProps = function (store) {
    console.log(`mapStateToProps ${store}`);
    return {
        navigation: store.navigation
    };
};

export default Redux.connect(mapStateToProps)(NavigationHeader);
Amio.io
źródło
3

Kwestia

Oto kilka rzeczy, na które należy zwrócić uwagę, aby zrozumieć zachowanie połączonego komponentu w kodzie:

Arity of connectMatters:connect(mapStateToProps, mapDispatchToProps)

React-Redux wywołuje connectz pierwszym argumentem mapStateToPropsi drugim argumentem mapDispatchToProps.

Dlatego, chociaż zdałeś już swoje mapDispatchToProps, React-Redux w rzeczywistości traktuje to tak, jak mapStatedlatego, że jest to pierwszy argument. Nadal otrzymujesz wstrzykniętą onSubmitfunkcję w swoim komponencie, ponieważ zwrot mapStatejest scalany z właściwościami komponentu. Ale nie tak mapDispatchpowinno być wstrzykiwane.

Możesz używać mapDispatchbez definiowania mapState. Przekaż w nullmiejsce, mapStatea Twój komponent nie będzie podlegał zmianom w sklepie.

Podłączony komponent dispatchjest domyślnie odbierany , gdy nie mapDispatchpodano

Ponadto twój komponent otrzymuje, dispatchponieważ otrzymał nulldrugą pozycję za mapDispatch. Jeśli poprawnie przejdziesz mapDispatch, twój komponent nie zostanie odebrany dispatch.

Powszechna praktyka

Powyższe odpowiedzi wyjaśnia, dlaczego komponent zachowywał się w ten sposób. Chociaż powszechną praktyką jest po prostu przekazywanie kreatora akcji przy użyciu mapStateToPropsskrótu obiektu. I nazwij to w ramach swojego komponentu, onSubmitczyli:

import { setAddresses } from '../actions.js'

const Start = (props) => {
  // ... omitted
  return <div>
    {/** omitted */}
    <FlatButton 
       label='Does Not Work'
       onClick={this.props.setAddresses({
         pickup: this.refs.pickup.state.address,
         dropoff: this.refs.dropoff.state.address
       })} 
    />
  </div>
};

const mapStateToProps = { setAddresses };
export default connect(null, mapDispatchToProps)(Start)
wgao19
źródło
0

Jeśli nie podasz mapDispatchToPropsdrugiego argumentu, na przykład:

export default connect(mapStateToProps)(Checkbox)

wtedy automatycznie otrzymujesz wysyłkę do właściwości komponentu, więc możesz po prostu:

class SomeComp extends React.Component {
  constructor(props, context) {
    super(props, context);
  }
  componentDidMount() {
    this.props.dispatch(ACTION GOES HERE);
  }
....

bez mapDispatchToProps

Serge Nikolaev
źródło
0

Używam w ten sposób .. jego łatwy do zrozumienia pierwszy argument to mapStateToProps, a drugi argument to mapDispatchToProps na końcu połącz się z funkcją / klasą.

const mapStateToProps = (state) => {
  return {
    todos: getVisibleTodos(state.todos, state.visibilityFilter)
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    onTodoClick: (id) => {
      dispatch(toggleTodo(id))
    }
  }
}

export default connect(mapStateToProps,mapDispatchToProps)(TodoList);
Abdul Moiz
źródło
jeśli nie masz pierwszego argumentu, po prostu
podaj
0

Czasami ten błąd występuje również podczas zmiany kolejności funkcji komponentu podczas przekazywania do połączenia.

Niepoprawne zamówienie:

export default connect(mapDispatchToProps, mapStateToProps)(TodoList);

Właściwa kolejność:

export default connect(mapStateToProps,mapDispatchToProps)(TodoList);
Codiee
źródło
0

Pułapka, w którą niektórzy mogą wkroczyć, jest objęta tym pytaniem, ale nie została uwzględniona w odpowiedziach, ponieważ jest nieco inna w strukturze kodu, ale zwraca dokładnie ten sam błąd.

Ten błąd występuje podczas używania bindActionCreatorsi nieprzekazywaniadispatch funkcji

Kod błędu

import someComponent from './someComponent'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { someAction } from '../../../actions/someAction'

const mapStatToProps = (state) => {
    const { someState } = state.someState

    return {
        someState
    }
};

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        someAction
    });
};

export default connect(mapStatToProps, mapDispatchToProps)(someComponent)

Kod stały

import someComponent from './someComponent'
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux'
import { someAction } from '../../../actions/someAction'

const mapStatToProps = (state) => {
    const { someState } = state.someState

    return {
        someState
    }
};

const mapDispatchToProps = (dispatch) => {
    return bindActionCreators({
        someAction
    }, dispatch);
};

export default connect(mapStatToProps, mapDispatchToProps)(someComponent)

Brak funkcji dispatchw kodzie błędu

jestem Batmanem
źródło
0

Funkcja 'connect' React-redux przyjmuje dwa argumenty, pierwszy to mapStateToProps, a drugi to mapDispatchToProps sprawdź poniżej, np.

export default connect(mapStateToProps, mapDispatchToProps)(Index); `

Jeśli nie chcemy pobrać stanu z redux, ustawiamy wartość null zamiast mapStateToProps.

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

Sachin Metkari
źródło