Answer the question
In order to leave comments, you need to log in
Is it correct to handle data in a React component's container?
Hello, there is a component
components/pages/ShopPage.jsx
import React, { Component } from 'react';
import ProductSingle from '../products/ProductSingle';
import CatsListFilterShop from '../../containers/CatsListFilterShop';
import ProductsSortShop from '../../containers/ProductsSortShop';
import {Pagination} from "../../helpers/pagination";
import Breadcrumbs from "../../helpers/breadcrumbs";
class ShopPage extends Component {
componentDidMount() {
const { setProducts, setAllProducts } = this.props;
setAllProducts();
}
render(){
const {productsList, categories, isProductsReady, setPagination, currentPage, pager} = this.props;
const matchPath = this.props.match.path;
return (
<div className="container woocomm__container">
<div className="row woocomm__row">
<div className="col-xs-12">
<div className="woocomm__col">
<Breadcrumbs />
<div className="products__wrapper">
<div className="products__sidebar">
{isProductsReady && <CatsListFilterShop categories={categories} />}
</div>
<div className="products__content">
<div className="products__contentHeader">
<div className="products__contentHeaderTitle">Весь ассортимент</div>
<ProductsSortShop />
</div>
<div className="products__list">
{isProductsReady && (
productsList ? (
productsList.map( ( productData ) => {
return (
<div className={'good__item'} key={productData.id}>
<ProductSingle {...productData} matchPath={matchPath} />
</div>
);
})) : (
<div className="products__list-empty">В этой категории товаров нет</div>
)
)}
</div>
{pager && (
<Pagination
pager={pager}
page={currentPage}
setPagination={setPagination.bind(this)}
/>
)}
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default ShopPage;
containers/pages/ShopPage.js
import {connect} from 'react-redux';
import {setProducts, setAllProducts} from '../../actions/products';
import {setFilter, setPagination} from '../../actions/filter';
import ShopPage from '../../components/pages/ShopPage';
import {getPager} from "../../helpers/pagination";
import {getCategoryProductRelationsByCatSlug} from '../../helpers/getCategoryProductRelations';
function sortBy(products, sortBy){
switch(sortBy){
case 'price_asc':
return products && products.sort((a, b) => (a.regular_price - b.regular_price));
case 'price_desc':
return products && products.sort((a, b) => (b.regular_price - a.regular_price))
default:
return products && products;
}
}
function getVisibleProducts(products, filterBy, catsRelation){
switch(filterBy){
case "all":
return products && products;
default:
const productIDs = catsRelation[filterBy] ? catsRelation[filterBy] : [];
return products && products.filter(item => (productIDs.includes(item.id)));
}
}
function getPaginatedProducts(products, page, perPage){
const end = page * perPage;
const begin = end - perPage;
return products && products.slice(begin, end);
};
function getPages(visibleProducts, perPage){
return Math.ceil(visibleProducts && visibleProducts.length / perPage);
};
const mapStateToProps = ({products, filter}) => {
const categoriesRelationship = getCategoryProductRelationsByCatSlug( products.items.categoriesRelationship );
const visibleProducts = getVisibleProducts(
products.items.productsList,
filter.filterShopBy,
categoriesRelationship
);
const sortedProducts = sortBy(
visibleProducts,
filter.sortProductShopBy
);
/* START: Pagination */
const perPage = 9;
const currentPage = filter.page || 1;
const paginatedProducts = getPaginatedProducts(
sortedProducts,
currentPage,
perPage
);
const pager = getPager(
visibleProducts && visibleProducts.length,
currentPage,
perPage
);
/* END: Pagination */
return {
productsList: paginatedProducts,
categories: products.items.categories,
categoriesRelationship: categoriesRelationship,
isProductsReady: products.isProductsReady,
filterBy: filter.filterShopBy,
sortProductShopBy: filter.sortProductShopBy,
pager: pager,
currentPage: currentPage,
}
};
const mapDispatchToProps = dispatch => ({
setAllProducts: () => dispatch(setAllProducts()),
setProducts: products => dispatch(setProducts(products)),
setPagination: page => dispatch(setPagination(page)),
setFilter,
});
export default connect(mapStateToProps, mapDispatchToProps)(ShopPage);
actions/products.js
import {
SET_PRODUCTS,
SET_PRODUCTS_SUCCEEDED,
SET_PRODUCTS_FAILED,
} from './types/product-types';
export const setAllProducts = () => {
return async dispatch => {
dispatch({type: SET_PRODUCTS});
axios.get('/api/products').then(({data}) =>{
dispatch({type: SET_PRODUCTS_SUCCEEDED, payload: data});
}).catch(err => {
dispatch({type: SET_PRODUCTS_FAILED, payload: err});
});
};
};
reducers/products.js
import {
SET_PRODUCTS,
SET_PRODUCTS_SUCCEEDED,
SET_PRODUCTS_FAILED,
} from '../actions/types/product-types';
const INITIAL_STATE = {
isProductsReady: false,
isProductsLoading: false,
productsError: null,
items: [],
};
export default function (state = INITIAL_STATE,action){
switch (action.type) {
case SET_PRODUCTS:
return {
...state,
isProductsReady: false,
isProductsLoading: true,
};
case SET_PRODUCTS_SUCCEEDED:
return {
...state,
items: action.payload,
isProductsReady: true,
isProductsLoading: false,
};
case SET_PRODUCTS_FAILED:
return {
...state,
isProductsReady: false,
isProductsLoading: false,
productsError: action.payload
};
default:
return state;
}
}
Answer the question
In order to leave comments, you need to log in
You can do this, you can also in the reducer, or actions. Actions with data should be done where it is appropriate, and the relevance depends on what exactly you are doing.
If this logic is only for this component, in order to bring the data from the format in which it is in the store to the format that the component needs, and it makes no sense to put the filtered data in the store - filter in the connection.
If this filtering is needed at the data level in the store (that is, to filter the data that came from somewhere before converting it to the format that should be in the store) - filter in reducers or actions.
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question