如何从ReactJS + Redux应用程序正确进行REST调用? [英] How to properly make REST calls from ReactJS + Redux application?

查看:107
本文介绍了如何从ReactJS + Redux应用程序正确进行REST调用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用ReactJS + Redux,以及Express和Webpack.有一个内置的API,我希望能够从客户端进行REST调用-GET,POST,PUT,DELETE.

I'm using ReactJS + Redux, along with Express and Webpack. There is an API built, and I want to be able to make REST calls -- GET, POST, PUT, DELETE -- from the client-side.

Redux架构如何以及正确的方法是什么?就简化程序,动作创建者,存储和反应路线而言,任何关于流程的良好示例都将非常有帮助.

How and what is the properly way to go about doing so with the Redux architecture? Any good example of the flow, in terms of reducers, action creators, store, and react routes, would be extremely helpful.

提前谢谢!

推荐答案

最简单的方法是使用redux-thunk程序包.该软件包是一个redux中间件,因此,首先,您应该将其连接到redux:

The simpliest way, is to do it using redux-thunk package. This package is an redux middleware, so first of all, you should connect it to redux:

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';

const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);

这使您可以将async动作与常规的sync动作一起分派.让我们创建其中之一:

This allows you to dispatch async actions along with regular sync actions. Let's create one of them:

// 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
          });
        }
      });
  }
}

我更喜欢将表述组件和容器组件上的react组件分开. 本文.

I prefer to separate react components on presentational and container components. This approach was perfectly described in this article.

接下来,我们应该创建TodosContainer组件,该组件将为表示性的Todos组件提供数据.在这里,我们使用的是react-redux库:

Next, we should create TodosContainer component, which would provide data to presentational Todos component. Here, we are using react-redux library:

// 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);

此外,您还应该创建todosReducer,它可以处理FETCH_TODOS_SUCCESS动作,如果要显示加载程序/错误消息,还可以创建另外两个动作.

Also, you should create todosReducer, which will handle FETCH_TODOS_SUCCESS action, and other 2 actions if you want display loader / error message.

// 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
});

对于其他操作,例如CREATEUPDATEDELETE,没有什么特别的,它们以相同的方式实现.

For other operations like CREATE, UPDATE, DELETE there is nothing special, they are implementing the same way.

这篇关于如何从ReactJS + Redux应用程序正确进行REST调用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆