React Redux 从后端方法获取数据 [英] React Redux fetching data from backend approach

查看:85
本文介绍了React Redux 从后端方法获取数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有点困惑,希望得到一个能帮助我理清思路的答案.假设我有一个后端(nodejs、express 等),我在其中存储我的用户及其数据,有时我想从后端获取数据,例如登录后的用户信息,或产品列表并保存他们在州内.

I'm a bit confused and would love an answer that will help me to clear my thoughts. Let's say I have a backend (nodejs, express etc..) where I store my users and their data, and sometimes I wanna fetch data from the backend, such as the user info after he logs in, or a list of products and save them in the state.

到目前为止我的方法和我所看到的,我在组件加载之前获取数据并使用响应中的数据分派一个动作.但我最近开始深入研究这个,我看到了我之前知道的 react-thunk 库,并开始怀疑从后端/API 获取的最佳实践是什么?React Hooks 对这个话题有什么改变吗?知道这一点很重要吗?

My approach so far and what I've seen, I fetch the data before the component loads and dispatch an action with the data from the response. But I recently started digging a bit about this and I saw react-thunk library which I knew earlier and started to wonder if what is the best practice of fetching from backend/API? Has React Hooks change anything about this topic? Is it important to know this?

我觉得有点笨,但找不到完全谈论这个话题的文章或视频:)

I feel a bit dumb but couldn't find an article or video that talks exactly about this topic :)

推荐答案

要实现此最佳实践,请使用以下方法:

To do this best practice, use the following method:

我使用了一些包和模式以获得最佳实践:

I used some packages and patterns for best practice:

  • redux-logger 用于记录浏览器控制台中的操作和状态.
  • reselect 选择器可以计算派生数据,允许 Redux存储尽可能少的状态等
  • redux-thunk Thunk 是推荐的基本中间件Redux 副作用逻辑,包括复杂的同步逻辑需要访问商店,以及简单的异步逻辑,比如 AJAX 请求等等
  • axios 用于 api(基于 Promise 的 HTTP 客户端,用于浏览器和 node.js)
  • redux-logger for log actions and states in console of browser.
  • reselect Selectors can compute derived data, allowing Redux to store the minimal possible state and etc.
  • redux-thunk Thunks are the recommended middleware for basic Redux side effects logic, including complex synchronous logic that needs access to the store, and simple async logic like AJAX requests and etc.
  • axios for work with api (Promise based HTTP client for the browser and node.js)

按名称 redux 或您喜欢的任何名称在 src 文件夹 中创建一个目录,然后然后在redux目录下创建两个文件store.jsrootReducer.js.我们假设从 API 获取产品.

create a directory by name redux or any name of you like in src folder and then create two files store.js and rootReducer.js in redux directory. We assume fetch products from API.

要做到这一点:

在 redux 目录中创建一个名为 product 的新目录,然后按名称创建四个文件 product.types.js, product.actions.js,redux/product目录

Create a new directory by name product in redux directory and then create four files by names product.types.js, product.actions.js, product.reducer.js, product.selector.js in redux/product directory

项目的结构应该如下

...
src
  App.js
  redux
    product
      product.types.js
      product.actions.js
      product.reducer.js
    rootReducer.js
    store.js
 Index.js
package.json
...

store.js

在这个文件中我们进行了 redux 配置

In this file we do the redux configuration

// redux/store.js:
import { createStore, applyMiddleware } from "redux";
import logger from "redux-logger";
import thunk from "redux-thunk";

import rootReducer from "./root-reducer";

const middlewares = [logger, thunk];

export const store = createStore(rootReducer, applyMiddleware(...middlewares));

rootReducer.js

combineReducers 辅助函数转换一个对象,其值为您可以将不同的归约函数合并为一个归约函数传递给 createStore.

The combineReducers helper function turns an object whose values are different reducing functions into a single reducing function you can pass to createStore.

// redux/rootReducer.js
import { combineReducers } from "redux";

import productReducer from "./product/product.reducer";

const rootReducer = combineReducers({
  shop: productReducer,
});

export default rootReducer;

product.types.js在这个文件中,我们定义了用于管理操作类型的常量.

product.types.js In this file we define constants for manage types of actions.

export const ShopActionTypes = {
  FETCH_PRODUCTS_START: "FETCH_PRODUCTS_START",
  FETCH_PRODUCTS_SUCCESS: "FETCH_PRODUCTS_SUCCESS",
  FETCH_PRODUCTS_FAILURE: "FETCH_PRODUCTS_FAILURE"
};

product.actions.js在这个文件中,我们为处理动作创建动作创建器.

product.actions.js In this file we create action creators for handle actions.

// redux/product/product.actions.js
import { ShopActionTypes } from "./product.types";
import axios from "axios";

export const fetchProductsStart = () => ({
  type: ShopActionTypes.FETCH_PRODUCTS_START
});

export const fetchProductsSuccess = products => ({
  type: ShopActionTypes.FETCH_PRODUCTS_SUCCESS,
  payload: products
});

export const fetchProductsFailure = error => ({
  type: ShopActionTypes.FETCH_PRODUCTS_FAILURE,
  payload: error
});

export const fetchProductsStartAsync = () => {
  return dispatch => {
    dispatch(fetchProductsStart());
    axios
      .get(url)
      .then(response => dispatch(fetchProductsSuccess(response.data.data)))
      .catch(error => dispatch(fetchProductsFailure(error)));
  };
};

product.reducer.js在这个文件中,我们为处理动作创建了 productReducer 函数.

product.reducer.js In this file we create productReducer function for handle actions.

import { ShopActionTypes } from "./product.types";

const INITIAL_STATE = {
  products: [],
  isFetching: false,
  errorMessage: undefined,
};

const productReducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case ShopActionTypes.FETCH_PRODUCTS_START:
      return {
        ...state,
        isFetching: true
      };
    case ShopActionTypes.FETCH_PRODUCTS_SUCCESS:
      return {
        ...state,
        products: action.payload,
        isFetching: false
      };
    case ShopActionTypes.FETCH_PRODUCTS_FAILURE:
      return {
        ...state,
        isFetching: false,
        errorMessage: action.payload
      };
    default:
      return state;
  }
};

export default productReducer;

product.selector.js在此文件中,我们从商店状态中选择 productsisFetching.

product.selector.js In this file we select products and isFetching from shop state.

import { createSelector } from "reselect";

const selectShop = state => state.shop;

export const selectProducts = createSelector(
  [selectShop],
  shop => shop.products
);

export const selectIsProductsFetching = createSelector(
  [selectShop],
  shop => shop.isFetching
);

Index.js在这个文件中,使用 Provider 包装了整个应用程序和组件,以便访问商店和状态的子组件.

Index.js In this file wrapped whole app and components with Provider for access child components to the store and states.

// src/Index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";

import { Provider } from "react-redux";
import { store } from "./redux/store";

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

App.js 类组件在这个文件中,我们使用类组件连接到商店和状态

App.js class component In this file we do connect to the store and states with class component

// src/App.js
import React, { Component } from "react";

import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
  selectIsProductsFetching,
  selectProducts
} from "./redux/product/product.selectors";

import { fetchProductsStartAsync } from "./redux/product/product.actions";

class App extends Component {
  componentDidMount() {
    const { fetchProductsStartAsync } = this.props;
    fetchProductsStartAsync();
  }

  render() {
    const { products, isProductsFetching } = this.props;
    console.log('products', products);
    console.log('isProductsFetching', isProductsFetching);
    return (
      <div className="App">Please see console in browser</div>
    );
  }
}

const mapStateToProps = createStructuredSelector({
  products: selectProducts,
  isProductsFetching: selectIsProductsFetching,
});

const mapDispatchToProps = dispatch => ({
  fetchProductsStartAsync: () => dispatch(fetchProductsStartAsync())
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);

或带有功能组件( useEffect hook )的 App.js在这个文件中,我们确实连接到商店并使用功能组件进行状态

or App.js with functional component ( useEffect hook ) In this file we do connect to the store and states with functional component

// src/App.js
import React, { Component, useEffect } from "react";

import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
  selectIsProductsFetching,
  selectProducts
} from "./redux/product/product.selectors";

import { fetchProductsStartAsync } from "./redux/product/product.actions";

const App = ({ fetchProductsStartAsync, products, isProductsFetching}) => {
  useEffect(() => {
    fetchProductsStartAsync();
  },[]);

    console.log('products', products);
    console.log('isProductsFetching', isProductsFetching);

    return (
      <div className="App">Please see console in browser</div>
    );
}

const mapStateToProps = createStructuredSelector({
  products: selectProducts,
  isProductsFetching: selectIsProductsFetching,
});

const mapDispatchToProps = dispatch => ({
  fetchProductsStartAsync: () => dispatch(fetchProductsStartAsync())
});

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);

这篇关于React Redux 从后端方法获取数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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