如何从ReactJS + Redux应用程序正确地进行REST调用?

Jo *_* Ko 27 html javascript reactjs react-jsx redux

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

使用Redux架构如何以及正确的方法是什么?就减速器,动作创建器,存储和反应路线而言,任何流程的良好示例都将非常有用.

先感谢您!

1ve*_*ven 29

最简单的方法是使用redux-thunk包来做.这个包是一个redux中间件,所以首先,你应该将它连接到redux:

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

const store = createStore(
  rootReducer,
  applyMiddleware(thunk)
);
Run Code Online (Sandbox Code Playgroud)

这允许您async与常规sync操作一起分派操作.让我们创建其中一个:

// 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
          });
        }
      });
  }
}
Run Code Online (Sandbox Code Playgroud)

我更喜欢在表现和容器组件上分离反应组件.本文完美地描述了这种方法.

接下来,我们应该创建TodosContainer组件,它将为表示Todos组件提供数据.在这里,我们使用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);
Run Code Online (Sandbox Code Playgroud)

此外,如果需要显示加载器/错误消息,您应该创建todosReducer,它将处理FETCH_TODOS_SUCCESS操作,以及其他2个操作.

// 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
});
Run Code Online (Sandbox Code Playgroud)

对于其它操作喜欢CREATE,UPDATE,DELETE没有什么特别的,他们正在实施方式相同.