reducer react form javascript reactjs redux

javascript - react - Reaccionar: el creador de acciones no está llamando al reductor



redux saga (2)

Estoy haciendo una llamada asíncrona en mi creador de acciones y llamo a mi reductor con el resultado, pero por alguna razón no pude entender que el reductor no se llame.

actions.js (creador de acción y acción)

export const GET_FORMS = ''GET_FORMS'' export function getForms() { $.get("server url", function(result) { return { type: GET_FORMS, formlist: result.data.forms } }) }

reducrs.js

import { GET_FORMS } from ''../actions/actions'' export default function formAction(state = {forms:[]}, action) { console.log("received action"+action.type) switch (action.type) { case GET_FORMS: console.log("Action:"+action); return Object.assign({},state,{ forms:action.formlist }) default: return state } }

App.js

import React, { Component, PropTypes } from ''react'' import ReactDOM from ''react-dom''; import { bindActionCreators } from ''redux'' import { connect } from ''react-redux'' import auth from ''../auth'' import FormTable from ''../components/FormTable'' import * as FormActions from ''../actions/actions'' class App extends Component { constructor(props) { super(props); this.state = {forms: []}; } componentDidMount() { // for some reason if i write this.props.actions.getForms () i get an error // Uncaught Error: Actions must be plain objects. Use custom middleware for // async actions. FormActions.getForms(); } render() { const {forms,actions} = this.props console.log(forms); return ( <FormTable results={forms} actions = {actions} /> ) } } App.PropTypes = { forms: PropTypes.array.isRequired } function mapStateToProps() { const { forms:forms } = {forms:[]} return { forms } } function mapDispatchToProps(dispatch) { return { actions: bindActionCreators(FormActions, dispatch) } } export default connect( mapStateToProps, mapDispatchToProps )(App)


Hay algunas cosas aquí.

  1. Tu creador de acciones no devuelve la acción que está creando. $.get no devuelve una acción, por lo que $.get al dispatch no es productivo.

    Razonablemente, esto puede generar confusión acerca de cómo devolver una acción desde un creador de acciones asíncronas. Como es asincrónico, por naturaleza no puede devolver el resultado final (a menos que estés usando es7 async await). El patrón que estás intentando es idéntico a esto:

    class App extends Component { ... componentDidMount() { // Instead of calling getForms, do the same directly $.get(url, function(res) { return { type: GET_FORMS, forms: res }; }); } render() { ... } }

    Desde la API $.get sabemos que $.get devuelve un objeto jqXHR , no cualquier tipo de acción. Por lo tanto, debe usar el resultado en la devolución de llamada en sí mismo; no puede simplemente devolverlo. Aquí hay un ejemplo de cómo podría ser el componentDidMount (tenga en cuenta que la devolución de llamada está vinculada a this ):

    componentDidMount() { $.get(url, function(res) { this.props.dispatch({ type: GET_FORMS, forms: res }); }.bind(this)) }

  2. Hacer asincronías en su componente o creador de acciones es un anti-patrón, o al menos desalentado. En este caso, está definiendo la asincronización dentro de un creador de acciones, lo cual es genial. Pero también estás ejecutando la operación asíncrona, lo cual es malo. En su lugar, debe emplear algún tipo de middleware para manejar operaciones asincrónicas. El middleware son solo funciones que toman medidas y hacen cosas con ellas después de que se envían, y la más común para este propósito es redux-thunk . Usando redux-thunk , simplemente devuelve una función que acepta el dispatch como argumento. En este caso, tu creador de acciones se vería así:

    export function getForms() { return function(dispatch) { $.get(url, function(result) { dispatch({ type: GET_FORMS, forms: result }); }) } }

    Esto es muy similar a lo que ya está haciendo, excepto que está creando un thunk es solo una función que define otra función para su ejecución posterior, en lugar de realizar la operación asincrónica ahora , la está definiendo para su ejecución más tarde.

  3. En realidad no está enviando nada.

    El problema más simple de arreglar, pero definitivamente una barrera :) En componentDidMount , estás llamando al creador de acciones que has importado, pero no estás convocando a dispatch . Sin embargo, estás al 50% del camino, ya que pasaste a los creadores de la acción para connect , pero aunque lo hiciste, no llamaste a los creadores de acciones encuadernados que connect pases a los pilares;

    Por lo tanto, en lugar de llamar a FormActions.getForms() , debe llamar a this.props.actions.formActions() . El primero no está atado, pero el último sí lo está. Llamar a este último es lo mismo que hacer this.props.dispatch(FormActions.getForms()) .

  4. Y finalmente: no es necesario definir mapDispatchToProps en este caso. Puede pasar objetos a ese parámetro de connect . Vea abajo:

    // Instead of this export default connect(mapStateToProps, mapDispatchToProps)(App); // do this: export default connect(mapStateToProps, FormActions)(App); // creates the bound action creator ''this.props.getForms()''

    Esta es principalmente una elección de estilo, pero creo que este es un buen patrón :) Para los objetos de origen del creador de acción múltiple, puede hacer esto:

    export default connect(mapStateToProps, { ...FormActions, ...UserActions })(App);