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

查看:17
本文介绍了如何从 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 动作,如果你想显示加载器/错误消息,还有其他 2 个动作.

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天全站免登陆