una servicio react consumir consume con como apis javascript html reactjs redux react-jsx

javascript - servicio - react consume rest api



¿Cómo realizar correctamente las llamadas REST desde la aplicación ReactJS+Redux? (3)

Estoy usando ReactJS + Redux, junto con Express y Webpack. Se construyó una API y quiero poder realizar llamadas REST - GET, POST, PUT, DELETE - desde el lado del cliente.

¿Cómo y cuál es la forma correcta de hacerlo con la arquitectura Redux? Cualquier buen ejemplo del flujo, en términos de reductores, creadores de acción, almacenamiento y rutas de reacción, sería extremadamente útil.

¡Gracias de antemano!


Este es el caso de uso principal para bibliotecas como redux-thunk , redux-saga y redux-observable .

redux-thunk es el más simple, donde harías algo como esto:

import fetch from ''isomorphic-fetch'' export const REQUEST_POSTS = ''REQUEST_POSTS'' function requestPosts(subreddit) { return { type: REQUEST_POSTS, subreddit } } export const RECEIVE_POSTS = ''RECEIVE_POSTS'' function receivePosts(subreddit, json) { return { type: RECEIVE_POSTS, subreddit, posts: json.data.children.map(child => child.data), receivedAt: Date.now() } } // Meet our first thunk action creator! // Though its insides are different, you would use it just like any other action creator: // store.dispatch(fetchPosts(''reactjs'')) export function fetchPosts(subreddit) { // Thunk middleware knows how to handle functions. // It passes the dispatch method as an argument to the function, // thus making it able to dispatch actions itself. return function (dispatch) { // First dispatch: the app state is updated to inform // that the API call is starting. dispatch(requestPosts(subreddit)) // The function called by the thunk middleware can return a value, // that is passed on as the return value of the dispatch method. // In this case, we return a promise to wait for. // This is not required by thunk middleware, but it is convenient for us. return fetch(`http://www.reddit.com/r/${subreddit}.json`) .then(response => response.json()) .then(json => // We can dispatch many times! // Here, we update the app state with the results of the API call. dispatch(receivePosts(subreddit, json)) ) // In a real world app, you also want to // catch any error in the network call. } }

El ejemplo anterior se toma directamente de http://redux.js.org/docs/advanced/AsyncActions.html que es realmente la fuente definitiva de respuestas a su pregunta.


La respuesta corta es:

  1. redux no es una arquitectura
  2. Puedes usar cualquier biblioteca. Mucha gente en estos días usa la API fetch directamente.
  3. Para poder integrar redux con acciones asíncronas (que necesita para AJAX), necesita usar una biblioteca para ayudar. Los dos más populares son redux-thunk y redux-saga , como han dicho otros.

Para una biblioteca simple con muerte cerebral que puede colocar en su aplicación de redux, puede probar redux-crud-store . Descargo de responsabilidad: lo escribí. También puede leer la fuente de redux-crud-store si está interesado en integrar la API de búsqueda, u otro cliente de API, con redux-saga.


La forma más sencilla es hacerlo usando el paquete redux-thunk . Este paquete es un middleware de redux, por lo que primero debe conectarlo a redux:

import { createStore, applyMiddleware } from ''redux''; import thunk from ''redux-thunk''; import rootReducer from ''./reducers/index''; const store = createStore( rootReducer, applyMiddleware(thunk) );

Esto le permite enviar acciones async junto con acciones de sync regulares. Vamos a crear uno de ellos:

// actions.js export function fetchTodos() { // Instead of plain objects, we are returning function. return function(dispatch) { // Dispatching REQUEST action, which tells our app, that we are started requesting todos. dispatch({ type: ''FETCH_TODOS_REQUEST'' }); return fetch(''/api/todos'') // Here, we are getting json body(in our case it will contain `todos` or `error` prop, depending on request was failed or not) from server response // And providing `response` and `body` variables to the next chain. .then(response => response.json().then(body => ({ response, body }))) .then(({ response, body }) => { if (!response.ok) { // If request was failed, dispatching FAILURE action. dispatch({ type: ''FETCH_TODOS_FAILURE'', error: body.error }); } else { // When everything is ok, dispatching SUCCESS action. dispatch({ type: ''FETCH_TODOS_SUCCESS'', todos: body.todos }); } }); } }

Prefiero separar los componentes de reacción en los componentes de presentación y contenedor. Este enfoque fue perfectamente descrito en este artículo .

A continuación, deberíamos crear el componente TodosContainer , que proporcionaría datos al componente Todos presentación. Aquí, estamos usando la librería react-redux :

// TodosContainer.js import React, { Component } from ''react''; import { connect } from ''react-redux''; import { fetchTodos } from ''../actions''; class TodosContainer extends Component { componentDidMount() { // When container was mounted, we need to start fetching todos. this.props.fetchTodos(); } render() { // In some simple cases, it is not necessary to create separate `Todos` component. You can put todos markup directly here. return <Todos items={this.props.todos} /> } } // This function is used to convert redux global state to desired props. function mapStateToProps(state) { // `state` variable contains whole redux state. return { // I assume, you have `todos` state variable. // Todos will be available in container component as `this.props.todos` todos: state.todos }; } // This function is used to provide callbacks to container component. function mapDispatchToProps(dispatch) { return { // This function will be available in component as `this.props.fetchTodos` fetchTodos: function() { dispatch(fetchTodos()); } }; } // We are using `connect` function to wrap our component with special component, which will provide to container all needed data. export default connect(mapStateToProps, mapDispatchToProps)(TodosContainer);

Además, debe crear todosReducer , que manejará la acción FETCH_TODOS_SUCCESS , y otras 2 acciones si desea mostrar el cargador / mensaje de error.

// reducers.js import { combineReducers } from ''redux''; const INITIAL_STATE = { items: [], isFetching: false, error: undefined }; function todosReducer(state = INITIAL_STATE, action) { switch (action.type) { case ''FETCH_TODOS_REQUEST'': // This time, you may want to display loader in the UI. return Object.assign({}, state, { isFetching: true }); case ''FETCH_TODOS_SUCCESS'': // Adding derived todos to state return Object.assign({}, state, { isFetching: false, todos: action.todos }); case ''FETCH_TODOS_FAILURE'': // Providing error message to state, to be able display it in UI. return Object.assign({}, state, { isFetching: false, error: action.error }); default: return state; } } export default combineReducers({ todos: todosReducer });

Para otras operaciones como CREATE , UPDATE , DELETE , no hay nada especial, se están implementando de la misma manera.