Traiter une requête asynchrone avec React, Redux et Axios?

Je suis nouveau pour réagir JS et Redux et il a été trop accablant pour aller de l'avant. Je suis en train de faire une requête POST à l'aide de Axios, mais je suis incapable de le faire. Il se peut que je manque quelque chose dans le dossier des conteneurs. Ci-dessous est le code. Vérifier plnkr

mise à Jour: je reçois @@ @ redux-form / SET_SUBMIT_SUCCEEDEDED message après avoir soumis. Mais quand je vérifie l'onglet Réseau, Je ne vois pas l'appel à L'API. Et aussi quand je consolerai le soumis valeurs, Je ne vois que les valeurs nom et fullname. Il ne se compose pas de logo et de détails. Ce qui me manque?

fichier de composants

   import React, { PureComponent } from 'react'
   import PropTypes from 'prop-types'
   import { Field,reduxForm } from 'redux-form'
   import {   Columns,Column, TextArea, Label,Button  } from 'bloomer'
   import FormField from 'FormField'

   const validate = (values) => {
     const errors = {}
    const requiredFields = 
      ['organizationName','organizationFullName','organizationDetails']

    requiredFields.forEach((field) => {
     if (!values[field]) {
     errors[field] = 'This field can't be empty!'
    }
  })
     return errors
}

  const formConfig = {
   validate,
   form: 'createOrganization',
   enableReinitialize: true
   }

  export class CreateOrganization extends PureComponent {
   static propTypes = {
     isLoading:PropTypes.bool.isRequired,
     handleSubmit: PropTypes.func.isRequired, // from react-redux     
     submitting: PropTypes.bool.isRequired // from react-redux
    }
   onSubmit = data => {
     console.log(data)
   }
  render () {
     const { handleSubmit,submitting,isLoading } = this.props
      return (
        <Columns isCentered>
        <form onSubmit={handleSubmit(this.onSubmit.bind(this))} > 

          <Column isSize='3/6' >        
            <Label>Organization Name</Label>             
            <Field 
              name="organizationName"
              component={FormField}
              type="text"
              placeholder="Organization Name"
            />   
          </Column>       


          <Column isSize='3/6'>
            <Label>Organization Full Name</Label>              
            <Field
              name="organizationFullName"
              component={FormField}
              type="text"
              placeholder="Organization Full Name"
            />  
          </Column> 


           <Column isSize='3/6'>            
            <Label>Organization Logo</Label>              
            <Input                  
              name="organizationLogo"                  
              type="file"
              placeholder="Logo"
            /> 
          </Column>

          <Column isSize='3/6'>
            <Label>Organization Details</Label>         
                <TextArea placeholder={'Enter Details'} />               
          </Column>          


          <Column >
            <span className="create-button">
              <Button type="submit" isLoading={submitting || isLoading} isColor='primary'>
                Submit
              </Button>  
            </span> 
              <Button type="button" isColor='danger'>
                Cancel
              </Button>                
          </Column>  

        </form>
      </Columns>
    )    
  }
}

  export default reduxForm(formConfig)(CreateOrganization)

Fichier Conteneur

   import React, { PureComponent } from 'react'
   import PropTypes from 'prop-types'
   import { connect } from 'react-redux'
   import Loader from 'Loader'
   import organization from 'state/organization'
   import CreateOrganization from '../components/createOrganization'

   export class Create extends PureComponent {
   static propTypes = {    
     error: PropTypes.object,
     isLoaded: PropTypes.bool.isRequired,  
     create: PropTypes.func.isRequired,   
    }
    onSubmit = data => {
      this.props.create(data)
    }

    render () {
      const { isLoaded, error } = this.props
    return (      
       <CreateOrganization onSubmitForm={this.onSubmit} isLoading=
         {isLoading} />    
     )
   }
 }

   const mapStateToProps = state => ({
     error: organization.selectors.getError(state),
     isLoading: organization.selectors.isLoading(state)
   })

    const mapDispatchToProps = {
      create: organization.actions.create
    }


  export default connect(mapStateToProps, mapDispatchToProps)(Create)
17
demandé sur Shubham Khatri 2017-11-29 00:13:20

4 réponses

vos créateurs d'action redux doivent être simples, objet et doivent envoyer et agir avec une clé obligatoire type. Cependant en utilisant des middlewares personnalisés comme redux-thunk on pourrait appeler axios demande au sein de votre action de créateurs sans personnalisé middlewares vos créateurs d'action doivent retourner l'objet simple

votre créateur d'action ressemblera à

export function create (values) {

  return (dispatch) => {
     dispatch({type: CREATE_ORGANIZATION});
     axios.post('/url', values)   
        .then((res) =>{
            dispatch({type: CREATE_ORGANIZATION_SUCCESS, payload: res});
        })
        .catch((error)=> {
            dispatch({type: CREATE_ORGANIZATION_FAILURE, payload: error});
        })
  }

}

et votre réducteur

export default (state = initialState, action) => {
  const payload = action.payload

   switch (action.type) {    
    case CREATE:    

      return {
        ...state,
        loading: true,
        loaded: false
      }

    case CREATE_SUCCESS:
      return {
        ...state,
        data: state.data.concat(payload.data),
        loading: false,
        loaded: true,
        error: null
      }   

      }

    case CREATE_FAILURE:

      return {
        ...state,
        loading: false,
        loaded: true,
        error: payload
      }
    default:
      return state
  }
}

maintenant, tout en créant le magasin, vous pouvez le faire comme

import thunk from 'redux-thunk';
import { createStore, applyMiddleware } from 'redux';
const store = createStore(
  reducer,
  applyMiddleware(thunk)
);

en dehors de cela, vous devez également configurer le formulaire redux

vous devez utiliser combineReducers et Provider pour passer sur le magasin

import reducer from './reducer';
import { combineReducers } from 'redux';
import { reducer as formReducer } from 'redux-form'

export const rootReducer = combineReducers({
   reducer,
   form: formReducer
})

CodeSandbox

11
répondu Shubham Khatri 2018-01-09 06:03:05

Vous pouvez le faire facilement avec l'aide de redux-saga.

à Propos de redux-saga:

redux-saga est une bibliothèque qui vise à rendre les effets secondaires de l'application (c.-à-d. des choses asynchrones comme la collecte de données et des choses impures comme l'accès au cache du navigateur) plus faciles à gérer, plus efficaces à exécuter, simples à tester, et mieux à gérer les échecs.

Installation:

$ npm install --save redux-saga 

ou

$ yarn add redux-saga

référez-vous au lien : https://github.com/redux-saga/redux-saga

2
répondu Vikas Yadav 2017-12-01 06:40:46

les créateurs D'action Redux ne supportent apparemment pas les actions asynchrones, ce que vous essayez de faire avec la requête post. Redux Thunk devrait vous aider.

Vous aurez besoin d'un magasin.fichier js qui ressemble à ceci:

//npm install --save redux-thunk

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducer.js';

// Note: this API requires redux@>=3.1.0
const store = createStore(
  rootReducer,
  applyMiddleware(thunk) //needed so you can do async
);

voici à quoi ressemblerait votre fichier actions. Create devient un créateur d'action qui retourne une fonction qui exécute alors la requête post et vous permet d'y effectuer l'expédition vous permettant de mettre à jour votre store/état. :

import axios from 'axios'
import { CREATE_ORGANIZATION, CREATE_ORGANIZATION_SUCCESS, CREATE_ORGANIZATION_FAILURE,

       } from './constants'
import * as selectors from './selectors'

/*
  CREATE ORGANIZATION
*/
//uses redux-thunk to make the post call happen
export function create (values) {
  return function(dispatch) {
    return axios.post('/url', values).then((response) => {
      dispatch({ type: 'Insert-constant-here'})
      console.log(response);
    })
    }
  }

aussi, vous voudrez passer dans la méthode onSubmit que vous avez créée dans onSubmitForm comme ceci. Je ne suis pas sûr d'où vient isLoading parce que je ne le vois pas importé dans ce composant de conteneur donc vous pourriez vouloir regarder cela aussi.:

  <createOrganization onSubmitForm={this.onSubmit.bind(this)} isLoading={isLoading} />
1
répondu Dream_Cap 2017-12-01 07:03:05

je suggère d'utiliser redux-promesse-de middleware. Cette bibliothèque exige que l'action ait une propriété nommée payload c'est un promesse et c'est facile avec axios. Il intègre ensuite avec Redux pour le suffixe de la racine du type d'action (par exemple,GET_CUSTOMERS) avec PENDING,FULFILLED et REJECTED et déclenche ces actions.

tirer l'action est la même que toute autre action.

Magasin

import {applyMiddleware, compose, createStore} from 'redux';
import promiseMiddleware from 'redux-promise-middleware';
import reducer from './reducers';

let middleware = applyMiddleware(promiseMiddleware());
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const enhancer = composeEnhancers(middleware);

export default createStore(reducer, enhancer);

Action

export function getCustomers() {
  return {
    type: 'GET_CUSTOMERS',
    payload: axios.get('url/to/api')
      .then(res => {
        if (!res.ok) throw new Error('An error occurred.');
        return res;
      })
      .then(res => res.json())
      .catch(err => console.warn(err));
  };
}

Réducteur

export default function(state = initialState, action) => {
  switch (action.type) {
    case 'GET_CUSTOMERS_PENDING':
      // this means the call is pending in the browser and has not
      // yet returned a response
      ...
    case 'GET_CUSTOMERS_FULFILLED':
      // this means the call is successful and the response has been set
      // to action.payload
      ...
    case 'GET_CUSTOMERS_REJECTED':
      // this means the response was unsuccessful so you can handle that
      // error here
      ...
    default:
      return state;
  }
}
0
répondu Mike Perrenoud 2017-12-07 19:19:04