'dispatch' não é uma função quando argumento para mapToDispatchToProps () no Redux

124

Sou iniciante em javascript / redux / react, criando um pequeno aplicativo com redux, react-redux e react. Por algum motivo, ao usar a função mapDispatchToProps em conjunto com connect (ligação react-redux), recebo um TypeError indicando que o despacho não é uma função quando tento executar o prop resultante. No entanto, quando eu chamo o dispatch como suporte (consulte a função setAddr no código fornecido), ele funciona.

Estou curioso para saber por que isso ocorre, no exemplo de aplicativo TODO nos documentos redux, o método mapDispatchToProps está configurado da mesma maneira. Quando eu console.log (despacho) dentro da função, ele diz que despacho é do tipo objeto. Eu poderia continuar usando o despacho dessa maneira, mas me sentiria melhor sabendo por que isso está acontecendo antes de continuar com o redux. Estou usando o webpack com babel-loaders para compilar.

Meu código:

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

Felicidades.

manchar
fonte
Eu estava tendo esta questão e este me ajudou a resolvê-lo
Alex W

Respostas:

249

Se você deseja usar mapDispatchToPropssem mapStateToPropsusar apenas nullo primeiro argumento.

export default connect(null, mapDispatchToProps)(Start)

inostia
fonte
4
É isso que eu tenho procurado. Agora eu sei se eu quero apenas despachar algumas ações.
Imperador Krauser
Isso é exatamente algo que eu estava procurando. Obrigado pela solução perfeita. E se não precisarmos usar o mapDispatchToProps em nenhum de nossos componentes? É da mesma maneira que temos que lidar com esse cenário?
Arun Ramachandran 26/03
1
Se você não precisa mapDispatchToProps, apenas não acrescentar que argumento para connect:connect(mapStateToProps)(MyComponent)
inostia
107

Você está apenas perdendo o primeiro argumento para connect, que é o mapStateToPropsmétodo. Trecho do aplicativo 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
fonte
3
é obrigatório usar esse método? Este método apenas pega estado e se não precisarmos desse método?
Muneem Habib
6
@MuneemHabib ver a resposta das inostia para saber como não fornecer este método se você não precisa dele
Brandon
21

Usar

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

ao invés de

const StartContainer = connect(mapDispatchToProps)(Start)
Ann
fonte
5

Eu resolvi trocando os argumentos, eu estava usando

export default connect(mapDispatchToProps, mapStateToProps)(Checkbox)

o que está errado. O mapStateToPropstem que ser o primeiro argumento:

export default connect(mapStateToProps, mapDispatchToProps)(Checkbox)

Parece óbvio agora, mas pode ajudar alguém.

Amit Mittal
fonte
3

Eu precisava de um exemplo usando, React.Componententão eu estou postando:

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
fonte
3

Questão

Aqui estão algumas coisas a serem observadas para entender o comportamento do componente conectado no seu código:

A Aridade das connectMatérias:connect(mapStateToProps, mapDispatchToProps)

React-Redux chama connectcom o primeiro argumento mapStateToPropse o segundo argumento mapDispatchToProps.

Portanto, embora você tenha passado na sua mapDispatchToProps, o React-Redux trata isso como mapStatese fosse o primeiro argumento. Você ainda recebe a onSubmitfunção injetada em seu componente porque o retorno de mapStateé mesclado nos acessórios do seu componente. Mas não é assim que mapDispatchdeve ser injetado.

Você pode usar mapDispatchsem definir mapState. Passe no nulllugar de mapStatee seu componente não estará sujeito a alterações na loja.

O componente conectado recebe dispatchpor padrão, quando nenhum mapDispatché fornecido

Além disso, seu componente recebe dispatchporque recebeu nullsua segunda posição para mapDispatch. Se você passar corretamente mapDispatch, seu componente não receberá dispatch.

Prática comum

As respostas acima respondem por que o componente se comportou dessa maneira. Embora seja uma prática comum, você simplesmente transmite seu criador de ações usando mapStateToPropsa abreviação de objetos. E chame isso dentro do componente onSubmitIsso é:

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
fonte
0

Quando você não fornece mapDispatchToPropscomo segundo argumento, assim:

export default connect(mapStateToProps)(Checkbox)

então você está recebendo o envio automaticamente para os adereços do componente, para que você possa:

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

sem nenhum mapDispatchToProps

Serge Nikolaev
fonte
0

Eu estou usando assim .. é fácil entender o primeiro argumento é mapStateToProps e o segundo argumento é mapDispatchToProps no final, conectar-se à função / classe.

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
fonte
Se você não tem primeiro argumento depois é só passar null / indefinido e, em seguida, segundo argumento ..
Abdul Moiz
0

Às vezes, esse erro também ocorre quando você altera a ordem da função do componente ao passar para a conexão.

Pedido incorreto:

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

Ordem correta:

export default connect(mapStateToProps,mapDispatchToProps)(TodoList);
Codiee
fonte
0

Uma armadilha que alguns podem abordar é abordada por esta pergunta, mas não é abordada nas respostas, pois é um pouco diferente na estrutura do código, mas retorna exatamente o mesmo erro.

Este erro ocorre ao usar bindActionCreatorse não passar a dispatchfunção

Erro de código

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)

Código Fixo

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)

A função dispatchestava ausente no código de erro

eu sou o Batman
fonte
0

A função React-redux 'connect' aceita dois argumentos, primeiro é mapStateToProps e o segundo é mapDispatchToProps, verifique abaixo ex.

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

Se não queremos recuperar o estado do redux, definimos nulo em vez de mapStateToProps.

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

Sachin Metkari
fonte