我有些困惑,很想得到一个答案,可以帮助我理清思路。假设我有一个后端(nodejs,express等),我在其中存储用户及其数据,有时我想从后端获取数据,例如用户登录后的用户信息或产品列表并保存他们在状态。
到目前为止,我所看到的方法是,在组件加载之前获取数据,并使用响应中的数据调度操作。但是我最近开始对此进行深入研究,并且看到了我较早知道的React- Thunk库,并开始怀疑从后端/ API获取数据的最佳实践是什么?React Hooks对此主题有任何更改吗?重要的是要知道这一点吗?
我有点傻,但找不到与该主题完全相关的文章或视频:)
若要执行此最佳做法,请使用以下方法:
我使用了一些软件包和模式来进行最佳实践:
通过创建名称的目录 终极版 或像你的任何名称 src文件夹 ,然后创建两个文件store.js,并rootReducer.js在终极版目录。我们假设从API获取产品。
store.js
rootReducer.js
去做这个:
通过创建名称的新目录 的产品 在终极版目录中,然后通过名称创建四个文件product.types.js, product.actions.js, product.reducer.js, product.selector.js的redux/product目录
product.types.js, product.actions.js, product.reducer.js, product.selector.js
redux/product
项目的结构应如下
... src App.js redux product product.types.js product.actions.js product.reducer.js rootReducer.js store.js Index.js package.json ...
在此文件中,我们进行redux配置
// 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));
combineReducers辅助函数将值不同的归约函数的对象转换为可以传递给的单个归约函数createStore。
combineReducers
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 在此文件中,我们定义用于管理动作类型的常量。
export const ShopActionTypes = { FETCH_PRODUCTS_START: "FETCH_PRODUCTS_START", FETCH_PRODUCTS_SUCCESS: "FETCH_PRODUCTS_SUCCESS", FETCH_PRODUCTS_FAILURE: "FETCH_PRODUCTS_FAILURE" };
product.actions.js 在此文件中,我们创建处理动作的动作创建者。
// 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用于处理动作的函数。
productReducer
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 在这个文件中,我们选择products和isFetching从商店状态。
products
isFetching
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用于访问商店和州的子组件。
Provider
// 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类组件 在此文件中,我们确实连接到商店并使用类组件声明状态
// 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钩子)的App.js 在此文件中,我们确实连接到具有功能组件的商店和状态
// 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);