Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
580 views
in Technique[技术] by (71.8m points)

reactjs - React Redux fetching data from backend approach

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.

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 :)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

To do this best practice, use the following method:

I used some packages and patterns for best practice:

  • 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)

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.

To do this:

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

The structure of the project should be as follows

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

store.js

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

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

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...