web-dev-qa-db-fra.com

Gestion des requêtes asynchrones avec React, Redux et Axios?

Je suis nouveau sur React JS et Redux et c’est trop pénible pour y aller. J'essaie de faire une demande POST à l'aide d'Axios, mais je ne peux pas le faire. Peut-être qu'il me manque quelque chose dans le fichier conteneur. Ci-dessous le code. Vérifier plnkr

Mise à jour: Je reçois le message @@ redux-form/SET_SUBMIT_SUCCEEDED après la soumission. Mais lorsque je consulte l'onglet Réseau, je ne vois pas l'appel à l'API. Et aussi, lorsque je consolide les valeurs soumises, je ne vois que les valeurs name et fullname. Cela ne consiste pas en un logo et des détails. Qu'est-ce que je rate?

Fichier de composant

   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
HebleV

Vos créateurs d’action redux doivent être clairs, objectés et doivent envoyer et agir avec une clé obligatoire type. Cependant, en utilisant des middlewares personnalisés tels que redux-thunk, vous pouvez appeler la requête axios au sein de vos créateurs d’action, car sans middlewares personnalisé, vos créateurs d’action doivent retourner un objet brut 

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 ressemblera à

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 transférer 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

12
Shubham Khatri

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

À propos de redux-saga:

redux-saga

ou

$ fil ajouter redux-saga

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

2
Vikas Yadav

Les créateurs d'actions Redux ne prennent apparemment pas en charge les actions asynchrones, ce que vous essayez de faire avec la demande de publication. Redux Thunk devrait aider avec ceci. 

Vous voudrez un fichier store.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 d'actions. Create devient un créateur d'action qui renvoie une fonction qui exécute ensuite la demande de publication et vous permet d'effectuer la distribution à cet emplacement, vous permettant de mettre à jour votre magasin/é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);
    })
    }
  }

En outre, vous voudrez transmettre la méthode onSubmit que vous avez créée dans onSubmitForm comme ceci. Je ne sais pas d'où vient isLoading car je ne vois pas qu'il soit importé dans ce composant conteneur, alors vous voudrez peut-être aussi examiner cela.

  <createOrganization onSubmitForm={this.onSubmit.bind(this)} isLoading={isLoading} />
1
Dream_Cap

Je suggère d'utiliser redux-promise-middleware . Cette bibliothèque nécessite que l'action ait une propriété nommée payload qui est une promise et cela est facile avec axios. Il intègre ensuite Redux pour suffixer le type d'action racine (par exemple GET_CUSTOMERS) avec PENDING, FULFILLED et REJECTED et déclenche ces actions.

Lancer l'action est la même chose que n'importe quelle autre action.

Le 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
Mike Perrenoud